Lucene是一套用于全文檢索和搜尋的開源程式庫,一星期的研究實(shí)現(xiàn)了簡(jiǎn)單的基于cms新聞管理系統(tǒng)的全文搜索引擎,自己做筆記記錄一下实蔽,個(gè)人理解可以把lucene當(dāng)做一個(gè)文檔型數(shù)據(jù)庫:
首先先了解lucene:
? 百科是這樣說的:Lucene是apache軟件基金會(huì)4 jakarta項(xiàng)目組的一個(gè)子項(xiàng)目卷扮,是一個(gè)開放源代碼的全文檢索引擎工具包荡澎,即它不是一個(gè)完整的全文檢索引擎,而是一個(gè)全文檢索引擎的架構(gòu)晤锹,提供了完整的查詢引擎和索引引擎摩幔,部分文本分析引擎(英文與德文兩種西方語言)。Lucene的目的是為軟件開發(fā)人員提供一個(gè)簡(jiǎn)單易用的工具包鞭铆,以方便的在目標(biāo)系統(tǒng)中實(shí)現(xiàn)全文檢索的功能或衡,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。
lucene常用類
?(1)IndexWriter?索引過程的核心組件车遂。這個(gè)類負(fù)責(zé)創(chuàng)建新索引或者打開已有索引封断,以及向索引中添加、刪除或更新索引文檔的信息舶担∑绿郏可以把IndexWriter看做這樣一個(gè)對(duì)象:提供針對(duì)索引文件的寫入操作,但不能用于讀取或搜索索引衣陶。IndexWriter需要開辟一定空間來存儲(chǔ)索引柄瑰,該功能可以由Directory完成。
?(2)Diretory索引存放的位置剪况,它是一個(gè)抽象類教沾,它的子類負(fù)責(zé)具體制定索引的存儲(chǔ)路徑。lucene提供了兩種索引存放的位置拯欧,一種是磁盤详囤,一種是內(nèi)存。一般情況將索引放在磁盤上;相應(yīng)地lucene提供了FSDirectory和RAMDirectory兩個(gè)類藏姐。
(3)Analyzer?分析器,主要用于分析搜索引擎遇到的各種文本隆箩,Analyzer的工作是一個(gè)復(fù)雜的過程:把一個(gè)字符串按某種規(guī)則劃分成一個(gè)個(gè)詞語,并去除其中的無效詞語(停用詞)羔杨,這里說的無效詞語如英文中的“of”捌臊、“the”,中文中的“的”兜材、“地”等詞語理澎,這些詞語在文章中大量出現(xiàn),但是本身不包含什么關(guān)鍵信息曙寡,去掉有利于縮小索引文件糠爬、提高效率、提高命中率举庶。分詞的規(guī)則千變?nèi)f化执隧,但目的只有一個(gè):按語義劃分。這點(diǎn)在英文中比較容易實(shí)現(xiàn)户侥,因?yàn)橛⑽谋旧砭褪且詥卧~為單位的镀琉,已經(jīng)用空格分開;而中文則必須以某種方法將連成一片的句子劃分成一個(gè)個(gè)詞語蕊唐。具體劃分方法下面再詳細(xì)介紹屋摔,這里只需了解分析器的概念即可。
// 定義分詞器
// Analyzer analyzer = new IKAnalyzer();//分詞器
//Analyzer analyzer = new SimpleAnalyzer(Version.LUCENE_47);// 簡(jiǎn)單分詞器
// Analyzer analyzer3 = new CJKAnalyzer(VERSION);// 二元切分
Analyzer analyzer = new IKAnalyzer(true);// 語意分詞? 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ù)庫表的一條記錄等等,一條記錄經(jīng)過索引之后副瀑,就是以一個(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)題”、“正文”等信息域箕别,這些信息域就是通過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ǔ)的目的妥泉,就是為了搜索頁面顯示取值用的。
比如:商品名稱洞坑、商品價(jià)格盲链、商品id、商品圖片地址
否:不將field域中的內(nèi)容存儲(chǔ)到文檔域中检诗。不存儲(chǔ)匈仗,則搜索頁面中沒法獲取該field域的值。
比如:商品描述逢慌,由于商品描述在搜索頁面中不需要顯示悠轩,再加上商品描述的內(nèi)容比較多,所以就不需要進(jìn)行存儲(chǔ)攻泼。如果需要商品描述火架,則根據(jù)搜索出的商品ID去數(shù)據(jù)庫中查詢,然后顯示出商品描述信息即可忙菠。
? 根據(jù)開發(fā)需求選擇不同的Filed類型:我找到的常用類型
(6)IndexSearcher?是lucene中最基本的檢索工具何鸡,所有的檢索都會(huì)用到IndexSearcher工具。
?(7)IndexReader打開一個(gè)Directory讀取索引類牛欢。
? (8)Query?查詢,抽象類骡男,必須通過一系列子類來表述檢索的具體需求,lucene中支持模糊查詢傍睹,語義查詢隔盛,短語查詢,組合查詢等等,如有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:無意義鳄炉,檢索無結(jié)果杜耙。
4.SHOULD與MUST、SHOULD與MUST_NOT:SHOULD與MUST連用時(shí)迎膜,無意義泥技,結(jié)果為MUST子句的檢索結(jié)果。與MUST_NOT連用時(shí)磕仅,功能同MUST珊豹。
5.SHOULD與SHOULD:意思是 or? 表示“或”關(guān)系,最終檢索結(jié)果為所有檢索子句的并集榕订。
對(duì)于多條件查詢還有其他的一些實(shí)現(xiàn)類比如?MultiFieldQueryParser.parse()來創(chuàng)建一個(gè)Query有多個(gè)參數(shù)店茶,比較簡(jiǎn)單查下api就能明白。
(9)QueryParser?解析用戶的查詢字符串進(jìn)行搜索,是一個(gè)解析用戶輸入的工具劫恒,可以通過掃描用戶輸入的字符串贩幻,生成Query對(duì)象。
? (10)TopDocs?根據(jù)關(guān)鍵字搜索整個(gè)索引庫两嘴,然后對(duì)所有結(jié)果進(jìn)行排序,取指定條目的結(jié)果丛楚。
? (11)TokenStream Token分詞器Analyzer通過對(duì)文本的分析來建立TokenStreams(分詞數(shù)據(jù)流)。TokenStream是由一個(gè)個(gè)Token(分詞組成的數(shù)據(jù)流)憔辫。所以說Analyzer就代表著一個(gè)從文本數(shù)據(jù)中抽取索引詞(Term)的一種策略趣些。
?(12)AttributeSourceTokenStream即是從Document的域(field)中或者查詢條件中抽取一個(gè)個(gè)分詞而組成的一個(gè)數(shù)據(jù)流。TokenSteam中是一個(gè)個(gè)的分詞贰您,而每個(gè)分詞又是由一個(gè)個(gè)的屬性(Attribute)組成坏平。對(duì)于所有的分詞來說,每個(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);// 語意分詞? 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)建索引庫
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 {
// 索引庫的存儲(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();
// 寫入到目錄文件中
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 {
// 索引庫的存儲(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();
// 寫入到目錄文件中
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ù)名稱和類型分頁搜索
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 {
// 索引庫的存儲(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));
// 讀取索引庫的存儲(chǔ)目錄
ireader = DirectoryReader.open(directory);
// 搜索類
IndexSearcher isearcher = new IndexSearcher(ireader);
//開始
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)容中包含的詞語
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和類型不分頁搜索
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 {
// 索引庫的存儲(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));
// 讀取索引庫的存儲(chǔ)目錄
ireader = DirectoryReader.open(directory);
// 搜索類
IndexSearcher isearcher = new IndexSearcher(ireader);
//開始
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 {
// 索引庫的存儲(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()));
*/
//開始
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();
}
}
}