Springboot集成lucene4.7

Lucene是一套用于全文檢索和搜尋的開(kāi)源程式庫(kù),一星期的研究實(shí)現(xiàn)了簡(jiǎn)單的基于cms新聞管理系統(tǒng)的全文搜索引擎,自己做筆記記錄一下,個(gè)人理解可以把lucene當(dāng)做一個(gè)文檔型數(shù)據(jù)庫(kù):

首先先了解lucene:

? 百科是這樣說(shuō)的:Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目,是一個(gè)開(kāi)放源代碼的全文檢索引擎工具包,即它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎,部分文本分析引擎(英文與德文兩種西方語(yǔ)言)。Lucene的目的是為軟件開(kāi)發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。

lucene常用類

?(1)IndexWriter?索引過(guò)程的核心組件。這個(gè)類負(fù)責(zé)創(chuàng)建新索引或者打開(kāi)已有索引,以及向索引中添加、刪除或更新索引文檔的信息??梢园袸ndexWriter看做這樣一個(gè)對(duì)象:提供針對(duì)索引文件的寫(xiě)入操作,但不能用于讀取或搜索索引。IndexWriter需要開(kāi)辟一定空間來(lái)存儲(chǔ)索引,該功能可以由Directory完成。

?(2)Diretory索引存放的位置,它是一個(gè)抽象類,它的子類負(fù)責(zé)具體制定索引的存儲(chǔ)路徑。lucene提供了兩種索引存放的位置,一種是磁盤,一種是內(nèi)存。一般情況將索引放在磁盤上;相應(yīng)地lucene提供了FSDirectory和RAMDirectory兩個(gè)類。

(3)Analyzer?分析器,主要用于分析搜索引擎遇到的各種文本,Analyzer的工作是一個(gè)復(fù)雜的過(guò)程:把一個(gè)字符串按某種規(guī)則劃分成一個(gè)個(gè)詞語(yǔ),并去除其中的無(wú)效詞語(yǔ)(停用詞),這里說(shuō)的無(wú)效詞語(yǔ)如英文中的“of”、“the”,中文中的“的”、“地”等詞語(yǔ),這些詞語(yǔ)在文章中大量出現(xiàn),但是本身不包含什么關(guān)鍵信息,去掉有利于縮小索引文件、提高效率、提高命中率。分詞的規(guī)則千變?nèi)f化,但目的只有一個(gè):按語(yǔ)義劃分。這點(diǎn)在英文中比較容易實(shí)現(xiàn),因?yàn)橛⑽谋旧砭褪且詥卧~為單位的,已經(jīng)用空格分開(kāi);而中文則必須以某種方法將連成一片的句子劃分成一個(gè)個(gè)詞語(yǔ)。具體劃分方法下面再詳細(xì)介紹,這里只需了解分析器的概念即可。

// 定義分詞器

// Analyzer analyzer = new IKAnalyzer();//分詞器

//Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_47);// 簡(jiǎn)單分詞器

// Analyzer analyzer3 = new CJKAnalyzer(VERSION);// 二元切分

Analyzer analyzer = new IKAnalyzer(true);// 語(yǔ)意分詞? false關(guān)閉智能分詞 (對(duì)分詞的精度影響較大)

//Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);// 創(chuàng)建標(biāo)準(zhǔn)分詞器

? ?(4)Document?文檔 Document相當(dāng)于一個(gè)要進(jìn)行索引的單元,可以是文本文件、字符串或者數(shù)據(jù)庫(kù)表的一條記錄等等,一條記錄經(jīng)過(guò)索引之后,就是以一個(gè)Document的形式存儲(chǔ)在索引文件,索引的文件都必須轉(zhuǎn)化為Document對(duì)象才能進(jìn)行索引。

? ? ?Document doc = new Document();

? ?????Field content = null;

????????Field title = null;

????????Field createTime = null;

????????Field type = null;

????????doc.add(id);

????????doc.add(content);

????????doc.add(title);

????????doc.add(createTime);

????????doc.add(type);

(5)Field?一個(gè)Document可以包含多個(gè)信息域,比如一篇文章可以包含“標(biāo)題”、“正文”等信息域,這些信息域就是通過(guò)Field在Document中存儲(chǔ)的。選擇field還是比較重要的:

是否分詞(Tokenized)

是:對(duì)該field存儲(chǔ)的內(nèi)容進(jìn)行分詞,分詞的目的,就是為了索引。

  比如:商品名稱、商品描述、商品價(jià)格

否:不需要對(duì)field存儲(chǔ)的內(nèi)容進(jìn)行分詞,不分詞,不代表不索引,而是將整個(gè)內(nèi)容進(jìn)行索引。

  比如:商品id

是否索引(Indexed)

是:將分好的詞進(jìn)行索引,索引的目的,就是為了搜索。

  比如:商品名稱、商品描述、商品價(jià)格、商品id

否:不索引,也就是不對(duì)該field域進(jìn)行搜索。

是否存儲(chǔ)(Stored)

是:將field域中的內(nèi)容存儲(chǔ)到文檔域中。存儲(chǔ)的目的,就是為了搜索頁(yè)面顯示取值用的。

  比如:商品名稱、商品價(jià)格、商品id、商品圖片地址

否:不將field域中的內(nèi)容存儲(chǔ)到文檔域中。不存儲(chǔ),則搜索頁(yè)面中沒(méi)法獲取該field域的值。

  比如:商品描述,由于商品描述在搜索頁(yè)面中不需要顯示,再加上商品描述的內(nèi)容比較多,所以就不需要進(jìn)行存儲(chǔ)。如果需要商品描述,則根據(jù)搜索出的商品ID去數(shù)據(jù)庫(kù)中查詢,然后顯示出商品描述信息即可。

? 根據(jù)開(kāi)發(fā)需求選擇不同的Filed類型:我找到的常用類型

(6)IndexSearcher?是lucene中最基本的檢索工具,所有的檢索都會(huì)用到IndexSearcher工具。

?(7)IndexReader打開(kāi)一個(gè)Directory讀取索引類。

? (8)Query?查詢,抽象類,必須通過(guò)一系列子類來(lái)表述檢索的具體需求,lucene中支持模糊查詢,語(yǔ)義查詢,短語(yǔ)查詢,組合查詢等等,如有TermQuery,BooleanQuery,RangeQuery,WildcardQuery等一些類。

這個(gè)也是比較重要的:查詢的條件查詢:

BooleanClause用于表示布爾查詢子句關(guān)系的類,包括:BooleanClause.Occur.MUST,BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.SHOULD。有以下6種組合:

1.MUST和MUST:取得連個(gè)查詢子句的交集。

2.MUST和MUST_NOT:表示查詢結(jié)果中不能包含MUST_NOT所對(duì)應(yīng)得查詢子句的檢索結(jié)果。

3.MUST_NOT和MUST_NOT:無(wú)意義,檢索無(wú)結(jié)果。

4.SHOULD與MUST、SHOULD與MUST_NOT:SHOULD與MUST連用時(shí),無(wú)意義,結(jié)果為MUST子句的檢索結(jié)果。與MUST_NOT連用時(shí),功能同MUST。

5.SHOULD與SHOULD:意思是 or? 表示“或”關(guān)系,最終檢索結(jié)果為所有檢索子句的并集。

對(duì)于多條件查詢還有其他的一些實(shí)現(xiàn)類比如?MultiFieldQueryParser.parse()來(lái)創(chuàng)建一個(gè)Query有多個(gè)參數(shù),比較簡(jiǎn)單查下api就能明白。

(9)QueryParser?解析用戶的查詢字符串進(jìn)行搜索,是一個(gè)解析用戶輸入的工具,可以通過(guò)掃描用戶輸入的字符串,生成Query對(duì)象。

? (10)TopDocs?根據(jù)關(guān)鍵字搜索整個(gè)索引庫(kù),然后對(duì)所有結(jié)果進(jìn)行排序,取指定條目的結(jié)果。

? (11)TokenStream Token分詞器Analyzer通過(guò)對(duì)文本的分析來(lái)建立TokenStreams(分詞數(shù)據(jù)流)。TokenStream是由一個(gè)個(gè)Token(分詞組成的數(shù)據(jù)流)。所以說(shuō)Analyzer就代表著一個(gè)從文本數(shù)據(jù)中抽取索引詞(Term)的一種策略。

?(12)AttributeSourceTokenStream即是從Document的域(field)中或者查詢條件中抽取一個(gè)個(gè)分詞而組成的一個(gè)數(shù)據(jù)流。TokenSteam中是一個(gè)個(gè)的分詞,而每個(gè)分詞又是由一個(gè)個(gè)的屬性(Attribute)組成。對(duì)于所有的分詞來(lái)說(shuō),每個(gè)屬性只有一個(gè)實(shí)例。這些屬性都保存在AttributeSource中,而AttributeSource正是TokenStream的父類。

1.依賴注入:

<!-- ik.中文分詞器依賴-->

<dependency>

<groupId>com.janeluo</groupId>

<artifactId>ikanalyzer</artifactId>

<version>2012_u6</version>

</dependency>

<!-- lucene依賴 -->

<dependency>

<groupId>org.apache.lucene</groupId>

<artifactId>lucene-highlighter</artifactId>

<version>4.7.2</version>

</dependency>

2.實(shí)現(xiàn)的增刪改查:

package com.yunqi.cms.common;

import java.io.File;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import org.apache.lucene.analysis.Analyzer;

import org.apache.lucene.document.Document;

import org.apache.lucene.document.Field;

import org.apache.lucene.document.Field.Store;

import org.apache.lucene.document.StringField;

import org.apache.lucene.document.TextField;

import org.apache.lucene.index.DirectoryReader;

import org.apache.lucene.index.IndexWriter;

import org.apache.lucene.index.IndexWriterConfig;

import org.apache.lucene.queryparser.classic.QueryParser;

import org.apache.lucene.search.BooleanClause.Occur;

import org.apache.lucene.search.BooleanQuery;

import org.apache.lucene.search.IndexSearcher;

import org.apache.lucene.search.Query;

import org.apache.lucene.search.ScoreDoc;

import org.apache.lucene.search.TopDocs;

import org.apache.lucene.store.Directory;

import org.apache.lucene.store.FSDirectory;

import org.apache.lucene.util.Version;

import org.wltea.analyzer.lucene.IKAnalyzer;

import com.yunqi.cms.entity.Content;

import com.yunqi.cms.vo.ContentVO;

import com.yunqi.cms.vo.LuceneContentVO;

import com.yunqi.platform.common.page.PageList;

import com.yunqi.platform.utils.LocalDateTimeUtils;

import com.yunqi.platform.utils.SystemConfigure;

/**

*

* @ClassName: LuceneUtils?

* @Description: 全文檢索

* @author yangqq

* @date 2019年6月15日 上午11:45:00?

* @version V1.0?

* @Copyright: 2019 www.yunqi.com Inc. All rights reserved.

*/

public class LuceneUtils {

// 定義分詞器

// Analyzer analyzer = new IKAnalyzer();//分詞器

//Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_47);// 簡(jiǎn)單分詞器

// Analyzer analyzer3 = new CJKAnalyzer(VERSION);// 二元切分

Analyzer analyzer = new IKAnalyzer(true);// 語(yǔ)意分詞? false關(guān)閉智能分詞 (對(duì)分詞的精度影響較大)

//Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_47);// 創(chuàng)建一個(gè)分詞器

public String createIndex(Object t) throws IOException {

if (t == null) {

throw new RuntimeException("所傳對(duì)象不可為空");

}

LuceneContentVO contentvo = new LuceneContentVO();

if (t instanceof LuceneContentVO) {

contentvo = (LuceneContentVO) t;

// 創(chuàng)建Document對(duì)象

Document doc = new Document();

// 獲取每列數(shù)據(jù)

if (contentvo.getId() == null) {

throw new RuntimeException("新聞Id不可為空");

}

if (contentvo.getSiteId() == null) {

throw new RuntimeException("站點(diǎn)信息不存在");

}

if(contentvo.getTitle()==null){

throw new RuntimeException("所存內(nèi)容名稱不可為空");

}

if(contentvo.getType()==null){

throw new RuntimeException("文章所屬類型不可為空");

}

Field content = null;

Field title = null;

Field createTime = null;

Field type = null;

? ? ? ? Field id = new StringField("id", contentvo.getId().toString(),Store.YES);//標(biāo)題 StringField索引存儲(chǔ)不分詞?

title = new TextField("title",? contentvo.getTitle(), Store.YES);


//如果是普通新聞,Content內(nèi)容不存儲(chǔ),title標(biāo)題進(jìn)行分詞存儲(chǔ),醫(yī)生內(nèi)容的title不分詞

? ? ? ? if(contentvo.getType().equals(CmsCommon.CMS_NEWS)){

content = new TextField("content", "",Store.YES);//內(nèi)容 TextField索引存儲(chǔ)分詞?

? ? ? ? }else{

? ? ? ? if (contentvo.getContent() != null) {

content = new TextField("content", contentvo.getContent().toString(),Store.YES);?

} else {

content = new TextField("content", "",Store.YES);?

}

//title = new StringField("title", contentvo.getTitle(), Store.YES);

? ? ? ? }


if (contentvo.getCreateTime() != null) {

createTime = new StringField("createTime", LocalDateTimeUtils.formatDateTime(contentvo.getCreateTime()), Store.YES);

} else {

createTime = new StringField("createTime","", Store.YES);

}

type = new StringField("type", contentvo.getType(), Store.YES);

// 添加到Document中

doc.add(id);

doc.add(content);

doc.add(title);

doc.add(createTime);

doc.add(type);

if (contentvo.getSiteId() != null) {

String path = "";

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + contentvo.getSiteId() + "/lucence";

// 調(diào)用,創(chuàng)建索引庫(kù)

this.write(doc, path);

} else {

throw new RuntimeException("站點(diǎn)信息不存在");

}

System.out.println("id:" + contentvo.getId().toString());

}

return "成功";

}

// 初始化索引

public void initcreate(List<LuceneContentVO> list, Integer siteId) throws IOException {

String path = "";

if (siteId != null) {

// 創(chuàng)建儲(chǔ)存路徑

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + siteId + "/lucence";

delFolder(path);

}

if (list.size() > 0) {

for (LuceneContentVO contentvo : list) {

if (contentvo.getSiteId() == null) {

throw new RuntimeException("站點(diǎn)信息不存在");

}

if (contentvo.getId() == null) {

throw new RuntimeException("新聞Id不可為空");

}

if(contentvo.getTitle()==null){

throw new RuntimeException("所存內(nèi)容名稱不可為空");

}

if(contentvo.getType()==null){

throw new RuntimeException("文章所屬類型不可為空");

}

Field content = null;

Field title = null;

Field createTime = null;

Field type = null;

? ? ? ? Field id = new StringField("id", contentvo.getId().toString(),Store.YES);//標(biāo)題 StringField索引存儲(chǔ)不分詞?

title = new TextField("title",? contentvo.getTitle(), Store.YES);

//如果是普通新聞,Content內(nèi)容不存儲(chǔ),title標(biāo)題進(jìn)行分詞存儲(chǔ),醫(yī)生內(nèi)容的title不分詞

? ? ? ? if(contentvo.getType().equals(CmsCommon.CMS_NEWS)){

content = new TextField("content", "",Store.YES);//內(nèi)容 TextField索引存儲(chǔ)分詞?

? ? ? ? }else{

? ? ? ? if (contentvo.getContent() != null) {

content = new TextField("content", contentvo.getContent().toString(),Store.YES);?

} else {

content = new TextField("content", "",Store.YES);?

}

? ? ? ? }


if (contentvo.getCreateTime() != null) {

createTime = new StringField("createTime", LocalDateTimeUtils.formatDateTime(contentvo.getCreateTime()), Store.YES);

} else {

createTime = new StringField("createTime","", Store.YES);

}

type = new StringField("type", contentvo.getType(), Store.YES);

// 創(chuàng)建Document對(duì)象

Document doc = new Document();

// 給title加權(quán)

//title.setBoost(4f);

// 添加到Document中

doc.add(id);

doc.add(content);

doc.add(title);

doc.add(createTime);

doc.add(type);

Directory directory = null;

IndexWriterConfig config = null;

IndexWriter iwriter = null;

try {

// 索引庫(kù)的存儲(chǔ)目錄()

directory = FSDirectory.open(new File(path));

// 關(guān)聯(lián)當(dāng)前l(fā)ucence版本和分值器

config = new IndexWriterConfig(Version.LUCENE_47, analyzer);

// 傳入目錄和分詞器

iwriter = new IndexWriter(directory, config);

iwriter.commit();

// 寫(xiě)入到目錄文件中

iwriter.addDocument(doc);

// 提交事務(wù)

iwriter.commit();

// 關(guān)閉流

iwriter.close();

} catch (IOException e) {

e.printStackTrace();

} finally {

// 關(guān)閉流

iwriter.close();

}

}

}

}

// 刪除指定文件夾下所有文件

// param path 文件夾完整絕對(duì)路徑

public static boolean delAllFile(String path) {

boolean flag = false;

File file = new File(path);

if (!file.exists()) {

return flag;

}

if (!file.isDirectory()) {

return flag;

}

String[] tempList = file.list();

File temp = null;

for (int i = 0; i < tempList.length; i++) {

if (path.endsWith(File.separator)) {

temp = new File(path + tempList[i]);

} else {

temp = new File(path + File.separator + tempList[i]);

}

if (temp.isFile()) {

temp.delete();

}

if (temp.isDirectory()) {

delAllFile(path + "/" + tempList[i]);// 先刪除文件夾里面的文件

delFolder(path + "/" + tempList[i]);// 再刪除空文件夾

flag = true;

}

}

return flag;

}

// 刪除文件夾

// param folderPath 文件夾完整絕對(duì)路徑

public static void delFolder(String folderPath) {

try {

delAllFile(folderPath); // 刪除完里面所有內(nèi)容

String filePath = folderPath;

filePath = filePath.toString();

java.io.File myFilePath = new java.io.File(filePath);

myFilePath.delete(); // 刪除空文件夾

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 封裝一個(gè)方法,將關(guān)鍵字詞存儲(chǔ)到索引文件中

*

* @param doc

* @throws IOException

*/

public void write(Document doc, String dir) throws IOException {

Directory directory = null;

IndexWriterConfig config = null;

IndexWriter iwriter = null;

try {

// 索引庫(kù)的存儲(chǔ)目錄

directory = FSDirectory.open(new File(dir));

// 關(guān)聯(lián)當(dāng)前l(fā)ucence版本和分值器

config = new IndexWriterConfig(Version.LUCENE_47, analyzer);

// 傳入目錄和分詞器

iwriter = new IndexWriter(directory, config);

iwriter.commit();

// 寫(xiě)入到目錄文件中

iwriter.addDocument(doc);

// 提交事務(wù)

iwriter.commit();

} catch (IOException e) {

e.printStackTrace();

} finally {

// 關(guān)閉流

iwriter.close();

}

}

/**

* 修改

*

* @param Object

*/

public void updateDocument(Object t) throws IOException {

if (t == null) {

throw new RuntimeException("所傳對(duì)象不可為空");

}

try {

LuceneContentVO contentvo = new LuceneContentVO();

if (t instanceof LuceneContentVO) {

contentvo = (LuceneContentVO) t;

if (contentvo.getId() == null) {

throw new RuntimeException("所傳對(duì)象ID不可為空");

}

String path = "";

if (contentvo.getSiteId() != null) {

// 創(chuàng)建儲(chǔ)存路徑

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + contentvo.getSiteId() + "/lucence";

}

// 創(chuàng)建Document對(duì)象

Document doc = new Document();

if (contentvo.getSiteId() == null) {

throw new RuntimeException("站點(diǎn)信息不存在");

}

if (contentvo.getId() == null) {

throw new RuntimeException("新聞Id不可為空");

}

if(contentvo.getTitle()==null){

throw new RuntimeException("所存內(nèi)容名稱不可為空");

}

if(contentvo.getType()==null){

throw new RuntimeException("文章所屬類型不可為空");

}

Field content = null;

Field title = null;

Field createTime = null;

Field type = null;

? ? ? ? Field id = new StringField("id", contentvo.getId().toString(),Store.YES);//標(biāo)題 StringField索引存儲(chǔ)不分詞?

title = new TextField("title",? contentvo.getTitle(), Store.YES);

//如果是普通新聞,Content內(nèi)容不存儲(chǔ),title標(biāo)題進(jìn)行分詞存儲(chǔ),醫(yī)生內(nèi)容的title不分詞

? ? ? ? if(contentvo.getType().equals(CmsCommon.CMS_NEWS)){

content = new TextField("content", "",Store.YES);//內(nèi)容 TextField索引存儲(chǔ)分詞?

? ? ? ? }else{

? ? ? ? if (contentvo.getContent() != null) {

content = new TextField("content", contentvo.getContent().toString(),Store.YES);?

} else {

content = new TextField("content", "",Store.YES);?

}

//title = new StringField("title", contentvo.getTitle(), Store.YES);

? ? ? ? }


if (contentvo.getCreateTime() != null) {

createTime = new StringField("createTime", LocalDateTimeUtils.formatDateTime(contentvo.getCreateTime()), Store.YES);

} else {

createTime = new StringField("createTime","", Store.YES);

}

type = new StringField("type", contentvo.getType(), Store.YES);

// 添加到Document中

doc.add(id);

doc.add(content);

doc.add(title);

doc.add(createTime);

doc.add(type);

this.deleteDocuments(contentvo.getId(), contentvo.getSiteId(),contentvo.getType());

this.write(doc, path);

System.out.println("contentId:" + contentvo.getId().toString());

}

} catch (Exception e) {

e.printStackTrace();

}

}

// 根據(jù)名稱和類型分頁(yè)搜索

public PageList<ContentVO> searchPage(Content content) throws IOException {

Directory directory = null;

DirectoryReader ireader = null;

PageList<ContentVO> pageList = new PageList<>();

List<ContentVO> cList = new ArrayList<>();

if (content == null) {

throw new RuntimeException("查詢新聞信息不可為空");

}

int pageNow = content.getCurrentPage();

int pageSize = content.getPageSize();

try {

// 索引庫(kù)的存儲(chǔ)目錄

String path = "";

if (content.getSiteId() != null) {

// 創(chuàng)建儲(chǔ)存路徑

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + content.getSiteId() + "/lucence";

}

directory = FSDirectory.open(new File(path));

// 讀取索引庫(kù)的存儲(chǔ)目錄

ireader = DirectoryReader.open(directory);

// 搜索類

IndexSearcher isearcher = new IndexSearcher(ireader);

//開(kāi)始

BooleanQuery booleanQuery = new BooleanQuery();

// 條件一內(nèi)容中必須要有title標(biāo)題

QueryParser parser1 = new QueryParser(Version.LUCENE_47, "title", analyzer);

// 搜索

Query query1 = parser1.parse(content.getTitle());

booleanQuery.add(query1, Occur.SHOULD);

// 條件二內(nèi)容中包含的詞語(yǔ)

QueryParser parser2 = new QueryParser(Version.LUCENE_47, "content", analyzer);

Query query2 = parser2.parse(content.getTitle());

booleanQuery.add(query2, Occur.SHOULD);

TopDocs topDocs = isearcher.search(booleanQuery, pageSize * pageNow);

System.out.println("查詢到的條數(shù)\t" + topDocs.totalHits);

ScoreDoc[] scores = topDocs.scoreDocs;

int start = (pageNow - 1) * pageSize;

int end = pageSize * pageNow;

if (topDocs.totalHits <= end) {

for (int i = start; i < topDocs.totalHits; i++) {

Document hitDoc = isearcher.doc(scores[i].doc);

ContentVO co = new ContentVO();

co.setId(Integer.parseInt(hitDoc.get("id")));

co.setContent(hitDoc.get("content"));

co.setTitle(hitDoc.get("title"));

co.setCreateTime(LocalDateTimeUtils.parseDateTime(hitDoc.get("createTime")));

co.setMediaType(hitDoc.get("type"));

cList.add(co);

}

} else {

for (int i = start; i < end; i++) {

Document hitDoc = isearcher.doc(scores[i].doc);

ContentVO co = new ContentVO();

co.setId(Integer.parseInt(hitDoc.get("id")));

co.setContent(hitDoc.get("content"));

co.setTitle(hitDoc.get("title"));

co.setCreateTime(LocalDateTimeUtils.parseDateTime(hitDoc.get("createTime")));

co.setMediaType(hitDoc.get("type"));

cList.add(co);

}

}

pageList.setList(cList);

pageList.setPageSize(content.getPageSize());

pageList.setCurrentPage(content.getCurrentPage());

pageList.setTotalSize(topDocs.totalHits);

return pageList;

} catch (Exception e) {

e.printStackTrace();

} finally {

ireader.close();

directory.close();

}

return pageList;

}

// 根據(jù)id和類型不分頁(yè)搜索

public List<ContentVO> searchById(LuceneContentVO content) throws IOException {

Directory directory = null;

DirectoryReader ireader = null;

List<ContentVO> cList = new ArrayList<>();

if (content == null) {

throw new RuntimeException("查詢新聞信息不可為空");

}

try {

// 索引庫(kù)的存儲(chǔ)目錄

String path = "";

if (content.getSiteId() != null) {

// 創(chuàng)建儲(chǔ)存路徑

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + content.getSiteId() + "/lucence";

}

directory = FSDirectory.open(new File(path));

// 讀取索引庫(kù)的存儲(chǔ)目錄

ireader = DirectoryReader.open(directory);

// 搜索類

IndexSearcher isearcher = new IndexSearcher(ireader);

//開(kāi)始

BooleanQuery booleanQuery = new BooleanQuery();

// 條件一內(nèi)容中必須要有id

QueryParser parser1 = new QueryParser(Version.LUCENE_47, "id", analyzer);

// 搜索

Query query1 = parser1.parse(content.getId().toString());

// 條件二內(nèi)容type屬于醫(yī)生或者普通新聞

QueryParser parser2 = new QueryParser(Version.LUCENE_47, "type", analyzer);

Query query2 = parser2.parse(content.getType());

//Query query2 = parser2.parse("Y");

booleanQuery.add(query1, Occur.MUST);

booleanQuery.add(query2, Occur.MUST);

TopDocs topDocs = isearcher.search(booleanQuery, 1000);

System.out.println("查詢到的條數(shù)\t" + topDocs.totalHits);

ScoreDoc[] scores = topDocs.scoreDocs;

for (int i = 0; i < topDocs.totalHits; i++) {

Document hitDoc = isearcher.doc(scores[i].doc);

ContentVO co = new ContentVO();

co.setId(Integer.parseInt(hitDoc.get("id")));

co.setContent(hitDoc.get("content"));

co.setTitle(hitDoc.get("title"));

co.setCreateTime(LocalDateTimeUtils.parseDateTime(hitDoc.get("createTime")));

co.setMediaType(hitDoc.get("type"));

cList.add(co);

}

return cList;

} catch (Exception e) {

e.printStackTrace();

} finally {

ireader.close();

directory.close();

}

return cList;

}

/**

* 刪除文檔

*

* @throws IOException

*/

public void deleteDocuments(Integer id, Integer siteId,String type) throws IOException {

Directory directory = null;

IndexWriterConfig config = null;

IndexWriter iwriter = null;

try {

// 索引庫(kù)的存儲(chǔ)目錄

String path = "";

if (siteId != null) {

// 創(chuàng)建儲(chǔ)存路徑

String resUploadPath = SystemConfigure.getValue("res_upload_path");

path = resUploadPath + siteId + "/lucence";

}

directory = FSDirectory.open(new File(path));

// 關(guān)聯(lián)當(dāng)前l(fā)ucence版本和分值器

config = new IndexWriterConfig(Version.LUCENE_47, analyzer);

// 傳入目錄和分詞器

iwriter = new IndexWriter(directory, config);

/*// 刪除title中含有關(guān)鍵詞“contentId”的文檔

iwriter.deleteDocuments(new Term("id", id.toString()));

*/

//開(kāi)始

BooleanQuery booleanQuery = new BooleanQuery();

// 條件一內(nèi)容中必須要有id

QueryParser parser1 = new QueryParser(Version.LUCENE_47, "id", analyzer);

// 搜索

Query query1 = parser1.parse(id.toString());

// 條件二內(nèi)容type屬于醫(yī)生或者普通新聞

QueryParser parser2 = new QueryParser(Version.LUCENE_47, "type", analyzer);

Query query2 = parser2.parse(type);

booleanQuery.add(query1, Occur.MUST);

booleanQuery.add(query2, Occur.MUST);

iwriter.deleteDocuments(booleanQuery);

iwriter.commit();

System.out.println("刪除完成");

} catch (Exception e) {

e.printStackTrace();

} finally {

iwriter.close();

}

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄結(jié)構(gòu):1.全文檢索 2.Lucene入門3.Lucene進(jìn)階 全文檢索 一, 生活中的搜索:1.Win...
    CoderZS閱讀 1,808評(píng)論 0 12
  • 何為L(zhǎng)ucene.Net? Lucene.net是Lucene的.net移植版本,是一個(gè)開(kāi)源的全文檢索引擎開(kāi)發(fā)包,...
    做全棧攻城獅閱讀 1,147評(píng)論 0 0
  • 1. 案例分析:什么時(shí)全文檢索,如何實(shí)現(xiàn)全文檢索 ? 1.1 案例 ? 實(shí)現(xiàn)一個(gè)文件的搜索功能,通過(guò)關(guān)鍵字搜索文件...
    東方舵手閱讀 1,234評(píng)論 0 1
  • 寫(xiě)在前面:本文中用到的 Apache Lucene 版本號(hào)是 4.10.2 截止到文章發(fā)布時(shí)官方的最新版本是 6....
    SawyerZh閱讀 4,566評(píng)論 2 15
  • 12/26 今天聽(tīng)一位大咖分享,里面有提到: 若你做一件事,問(wèn)問(wèn)自己,你是不能做,而是不去做? 聽(tīng)過(guò)后,反思下自己...
    微風(fēng)嘻嘻閱讀 322評(píng)論 0 1

友情鏈接更多精彩內(nèi)容