使用Java的Lucene搜索工具對(duì)檢索結(jié)果進(jìn)行分組和分頁(yè)
使用GroupingSearch對(duì)搜索結(jié)果進(jìn)行分組
Package org.apache.lucene.search.grouping Description
這個(gè)模塊可以對(duì)Lucene的搜索結(jié)果進(jìn)行分組,指定的單值域被聚集到一起。比如,根據(jù)”author“域進(jìn)行分組,“author”域值相同的的文檔分成一個(gè)組。
進(jìn)行分組的時(shí)候需要輸入一些必要的信息:
1、groupField:根據(jù)這個(gè)域進(jìn)行分組。比如,如果你使用“author”域進(jìn)行分組,那么每一個(gè)組里面的書(shū)籍都是同一個(gè)作者。沒(méi)有這個(gè)域的文檔將被分到一個(gè)單獨(dú)的組里面。
2、groupSort:組排序。
3、topNGroups:保留多少組。比如,10表示只保留前10組。
4、groupOffset:對(duì)排在前面的哪些分組組進(jìn)行檢索。比如,3表示返回7個(gè)組(假設(shè)opNGroups等于10)。在分頁(yè)里面很有用,比如每頁(yè)只顯示5個(gè)組。
5、withinGroupSort:組內(nèi)文檔排序。注意:這里和groupSort的區(qū)別
6、withingroupOffset:對(duì)每一個(gè)分組里面的哪些排在前面的文檔進(jìn)行檢索。
使用GroupingSearch 對(duì)搜索結(jié)果分組比較簡(jiǎn)單
GroupingSearch API文檔介紹:
Convenience class to perform grouping in a non distributed environment.
非分布式環(huán)境下分組
WARNING: This API is experimental and might change in incompatible ways in the next release.
這里使用的是4.3.1版本
一些重要的方法:
- GroupingSearch:setCaching(int maxDocsToCache, boolean cacheScores) 緩存
- GroupingSearch:setCachingInMB(double maxCacheRAMMB, boolean cacheScores) 緩存第一次搜索結(jié)果,用于第二次搜索
- GroupingSearch:setGroupDocsLimit(int groupDocsLimit) 指定每組返回的文檔數(shù),不指定時(shí),默認(rèn)返回一個(gè)文檔
- GroupingSearch:setGroupSort(Sort groupSort) 指定分組排序
示例代碼:
1.先看建索引的代碼
public class IndexHelper {
private Document document;
private Directory directory;
private IndexWriter indexWriter;
public Directory getDirectory(){
directory=(directory==null)? new RAMDirectory():directory;
return directory;
}
private IndexWriterConfig getConfig() {
return new IndexWriterConfig(Version.LUCENE_43, new IKAnalyzer(true));
}
private IndexWriter getIndexWriter() {
try {
return new IndexWriter(getDirectory(), getConfig());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public IndexSearcher getIndexSearcher() throws IOException {
return new IndexSearcher(DirectoryReader.open(getDirectory()));
}
/**
* Create index for group test
* @param author
* @param content
*/
public void createIndexForGroup(int id,String author,String content) {
indexWriter = getIndexWriter();
document = new Document();
document.add(new IntField("id",id, Field.Store.YES));
document.add(new StringField("author", author, Field.Store.YES));
document.add(new TextField("content", content, Field.Store.YES));
try {
indexWriter.addDocument(document);
indexWriter.commit();
indexWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.分組:
public class GroupTest
public void group(IndexSearcher indexSearcher,String groupField,String content) throws IOException, ParseException {
GroupingSearch groupingSearch = new GroupingSearch(groupField);
groupingSearch.setGroupSort(new Sort(SortField.FIELD_SCORE));
groupingSearch.setFillSortFields(true);
groupingSearch.setCachingInMB(4.0, true);
groupingSearch.setAllGroups(true);
//groupingSearch.setAllGroupHeads(true);
groupingSearch.setGroupDocsLimit(10);
QueryParser parser = new QueryParser(Version.LUCENE_43, "content", new IKAnalyzer(true));
Query query = parser.parse(content);
TopGroups<BytesRef> result = groupingSearch.search(indexSearcher, query, 0, 1000);
System.out.println("搜索命中數(shù):" + result.totalHitCount);
System.out.println("搜索結(jié)果分組數(shù):" + result.groups.length);
Document document;
for (GroupDocs<BytesRef> groupDocs : result.groups) {
System.out.println("分組:" + groupDocs.groupValue.utf8ToString());
System.out.println("組內(nèi)記錄:" + groupDocs.totalHits);
//System.out.println("groupDocs.scoreDocs.length:" + groupDocs.scoreDocs.length);
for (ScoreDoc scoreDoc : groupDocs.scoreDocs) {
System.out.println(indexSearcher.doc(scoreDoc.doc));
}
}
}
3.簡(jiǎn)單的測(cè)試:
public static void main(String[] args) throws IOException, ParseException {
IndexHelper indexHelper = new IndexHelper();
indexHelper.createIndexForGroup(1,"紅薯", "開(kāi)源中國(guó)");
indexHelper.createIndexForGroup(2,"紅薯", "開(kāi)源社區(qū)");
indexHelper.createIndexForGroup(3,"紅薯", "代碼設(shè)計(jì)");
indexHelper.createIndexForGroup(4,"紅薯", "設(shè)計(jì)");
indexHelper.createIndexForGroup(5,"覺(jué)先", "Lucene開(kāi)發(fā)");
indexHelper.createIndexForGroup(6,"覺(jué)先", "Lucene實(shí)戰(zhàn)");
indexHelper.createIndexForGroup(7,"覺(jué)先", "開(kāi)源Lucene");
indexHelper.createIndexForGroup(8,"覺(jué)先", "開(kāi)源solr");
indexHelper.createIndexForGroup(9,"散仙", "散仙開(kāi)源Lucene");
indexHelper.createIndexForGroup(10,"散仙", "散仙開(kāi)源solr");
indexHelper.createIndexForGroup(11,"散仙", "開(kāi)源");
GroupTest groupTest = new GroupTest();
groupTest.group(indexHelper.getIndexSearcher(),"author", "開(kāi)源");
}
}
4.測(cè)試結(jié)果:

兩種分頁(yè)方式
Lucene有兩種分頁(yè)方式:
1、直接對(duì)搜索結(jié)果進(jìn)行分頁(yè),數(shù)據(jù)量比較少的時(shí)候可以用這種方式,分頁(yè)代碼核心參照:
ScoreDoc[] sd = XXX;
// 查詢起始記錄位置
int begin = pageSize * (currentPage - 1);
// 查詢終止記錄位置
int end = Math.min(begin + pageSize, sd.length);
for (int i = begin; i < end && i <totalHits; i++) {
//對(duì)搜索結(jié)果數(shù)據(jù)進(jìn)行處理的代碼
}
2、使用searchAfter(...)
Lucene提供了五個(gè)重載方法,可以根據(jù)需要使用

ScoreDoc after:為上次搜索結(jié)果ScoreDoc總量減1;
Query query:查詢方式
int n:為每次查詢返回的結(jié)果數(shù),即每頁(yè)的結(jié)果總量
一個(gè)簡(jiǎn)單的使用示例:
//可以使用Map保存必要的搜索結(jié)果
Map<String, Object> resultMap = new HashMap<String, Object>();
ScoreDoc after = null;
Query query = XX
TopDocs td = search.searchAfter(after, query, size);
//獲取命中數(shù)
resultMap.put("num", td.totalHits);
ScoreDoc[] sd = td.scoreDocs;
for (ScoreDoc scoreDoc : sd) {
//經(jīng)典的搜索結(jié)果處理
}
//搜索結(jié)果ScoreDoc總量減1
after = sd[td.scoreDocs.length - 1];
//保存after用于下次搜索,即下一頁(yè)開(kāi)始
resultMap.put("after", after);
return resultMap;
- Java分頁(yè)工具類及其使用(示例分享)
- Java Web 簡(jiǎn)單的分頁(yè)顯示實(shí)例代碼
- Java的MyBatis框架中實(shí)現(xiàn)多表連接查詢和查詢結(jié)果分頁(yè)
- Java簡(jiǎn)單實(shí)現(xiàn)SpringMVC+MyBatis分頁(yè)插件
- 舉例詳解用Java實(shí)現(xiàn)web分頁(yè)功能的方法
- js前臺(tái)分頁(yè)顯示后端JAVA數(shù)據(jù)響應(yīng)
- Java(基于Struts2) 分頁(yè)實(shí)現(xiàn)代碼
- 使用Jquery+Ajax+Json如何實(shí)現(xiàn)分頁(yè)顯示附JAVA+JQuery實(shí)現(xiàn)異步分頁(yè)
- Java操作MongoDB模糊查詢和分頁(yè)查詢
- java分頁(yè)工具類的使用方法
相關(guān)文章
SpringBoot讀寫(xiě)xml上傳到AWS存儲(chǔ)服務(wù)S3的示例
這篇文章主要介紹了SpringBoot讀寫(xiě)xml上傳到S3的示例,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-10-10
詳解Spring Boot工程集成全局唯一ID生成器 UidGenerator的操作步驟
本文就在項(xiàng)目中來(lái)集成 UidGenerator這一工程來(lái)作為項(xiàng)目的全局唯一 ID生成器。接下來(lái)通過(guò)實(shí)例代碼給大家詳解詳解Spring Boot工程集成全局唯一ID生成器 UidGenerator的操作步驟,感興趣的朋友一起看看吧2018-10-10
springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建)
這篇文章主要介紹了springboot-2.3.x最新版源碼閱讀環(huán)境搭建(基于gradle構(gòu)建),需要的朋友可以參考下2020-08-08
java實(shí)現(xiàn)微信支付結(jié)果通知
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信支付結(jié)果通知,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Maven默認(rèn)中央倉(cāng)庫(kù)(settings.xml 配置詳解)
這篇文章主要介紹了Maven默認(rèn)中央倉(cāng)庫(kù)(settings.xml 配置詳解),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12
ConstraintValidator類如何實(shí)現(xiàn)自定義注解校驗(yàn)前端傳參
這篇文章主要介紹了ConstraintValidator類實(shí)現(xiàn)自定義注解校驗(yàn)前端傳參的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
mybatis?plus框架@TableField注解不生效問(wèn)題及解決方案
最近遇到一個(gè)mybatis plus的問(wèn)題,@TableField注解不生效,導(dǎo)致查出來(lái)的字段反序列化后為空,今天通過(guò)本文給大家介紹下mybatis?plus框架的@TableField注解不生效問(wèn)題總結(jié),需要的朋友可以參考下2022-03-03
JAVA中使用JSON進(jìn)行數(shù)據(jù)傳遞示例
本篇文章主要介紹了JAVA中使用JSON進(jìn)行數(shù)據(jù)傳遞示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

