Springboot集成lucene4.7

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();

}

}

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市篮绿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吕漂,老刑警劉巖亲配,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡吼虎,警方通過查閱死者的電腦和手機(jī)犬钢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來思灰,“玉大人玷犹,你說我怎么就攤上這事∪骶危” “怎么了歹颓?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)油湖。 經(jīng)常有香客問我巍扛,道長(zhǎng),這世上最難降的妖魔是什么乏德? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任撤奸,我火速辦了婚禮,結(jié)果婚禮上喊括,老公的妹妹穿的比我還像新娘胧瓜。我一直安慰自己,他們只是感情好郑什,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布府喳。 她就那樣靜靜地躺著,像睡著了一般蹦误。 火紅的嫁衣襯著肌膚如雪劫拢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天强胰,我揣著相機(jī)與錄音舱沧,去河邊找鬼。 笑死偶洋,一個(gè)胖子當(dāng)著我的面吹牛熟吏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玄窝,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼牵寺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了恩脂?” 一聲冷哼從身側(cè)響起帽氓,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俩块,沒想到半個(gè)月后黎休,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浓领,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年势腮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了联贩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捎拯,死狀恐怖泪幌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情署照,我是刑警寧澤祸泪,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站藤树,受9級(jí)特大地震影響浴滴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岁钓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一升略、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屡限,春花似錦品嚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至啊央,卻和暖如春眶诈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓜饥。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工逝撬, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乓土。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓宪潮,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親趣苏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狡相,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

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