使用Java的Lucene搜索工具对检索结果进行分组和分页
作者:小檀 发布时间:2022-07-27 05:21:17
使用GroupingSearch对搜索结果进行分组
Package org.apache.lucene.search.grouping Description
这个模块可以对Lucene的搜索结果进行分组,指定的单值域被聚集到一起。比如,根据”author“域进行分组,“author”域值相同的的文档分成一个组。
进行分组的时候需要输入一些必要的信息:
1、groupField:根据这个域进行分组。比如,如果你使用“author”域进行分组,那么每一个组里面的书籍都是同一个作者。没有这个域的文档将被分到一个单独的组里面。
2、groupSort:组排序。
3、topNGroups:保留多少组。比如,10表示只保留前10组。
4、groupOffset:对排在前面的哪些分组组进行检索。比如,3表示返回7个组(假设opNGroups等于10)。在分页里面很有用,比如每页只显示5个组。
5、withinGroupSort:组内文档排序。注意:这里和groupSort的区别
6、withingroupOffset:对每一个分组里面的哪些排在前面的文档进行检索。
使用GroupingSearch 对搜索结果分组比较简单
GroupingSearch API文档介绍:
Convenience class to perform grouping in a non distributed environment.
非分布式环境下分组
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) 缓存第一次搜索结果,用于第二次搜索
GroupingSearch:setGroupDocsLimit(int groupDocsLimit) 指定每组返回的文档数,不指定时,默认返回一个文档
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("搜索命中数:" + result.totalHitCount);
System.out.println("搜索结果分组数:" + result.groups.length);
Document document;
for (GroupDocs<BytesRef> groupDocs : result.groups) {
System.out.println("分组:" + groupDocs.groupValue.utf8ToString());
System.out.println("组内记录:" + groupDocs.totalHits);
//System.out.println("groupDocs.scoreDocs.length:" + groupDocs.scoreDocs.length);
for (ScoreDoc scoreDoc : groupDocs.scoreDocs) {
System.out.println(indexSearcher.doc(scoreDoc.doc));
}
}
}
3.简单的测试:
public static void main(String[] args) throws IOException, ParseException {
IndexHelper indexHelper = new IndexHelper();
indexHelper.createIndexForGroup(1,"红薯", "开源中国");
indexHelper.createIndexForGroup(2,"红薯", "开源社区");
indexHelper.createIndexForGroup(3,"红薯", "代码设计");
indexHelper.createIndexForGroup(4,"红薯", "设计");
indexHelper.createIndexForGroup(5,"觉先", "Lucene开发");
indexHelper.createIndexForGroup(6,"觉先", "Lucene实战");
indexHelper.createIndexForGroup(7,"觉先", "开源Lucene");
indexHelper.createIndexForGroup(8,"觉先", "开源solr");
indexHelper.createIndexForGroup(9,"散仙", "散仙开源Lucene");
indexHelper.createIndexForGroup(10,"散仙", "散仙开源solr");
indexHelper.createIndexForGroup(11,"散仙", "开源");
GroupTest groupTest = new GroupTest();
groupTest.group(indexHelper.getIndexSearcher(),"author", "开源");
}
}
4.测试结果:
两种分页方式
Lucene有两种分页方式:
1、直接对搜索结果进行分页,数据量比较少的时候可以用这种方式,分页代码核心参照:
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++) {
//对搜索结果数据进行处理的代码
}
2、使用searchAfter(...)
Lucene提供了五个重载方法,可以根据需要使用
ScoreDoc after:为上次搜索结果ScoreDoc总量减1;
Query query:查询方式
int n:为每次查询返回的结果数,即每页的结果总量
一个简单的使用示例:
//可以使用Map保存必要的搜索结果
Map<String, Object> resultMap = new HashMap<String, Object>();
ScoreDoc after = null;
Query query = XX
TopDocs td = search.searchAfter(after, query, size);
//获取命中数
resultMap.put("num", td.totalHits);
ScoreDoc[] sd = td.scoreDocs;
for (ScoreDoc scoreDoc : sd) {
//经典的搜索结果处理
}
//搜索结果ScoreDoc总量减1
after = sd[td.scoreDocs.length - 1];
//保存after用于下次搜索,即下一页开始
resultMap.put("after", after);
return resultMap;


猜你喜欢
- 本文实例为大家分享了java实现人工智能化屏幕监控窗口的具体代码,供大家参考,具体内容如下具体代码实现(含注释)public class M
- 前言对于数组遍历,基本上每个开发者都写过,遍历本身没什么好说的,但是当我们在遍历的过程中,有一些复杂的业务逻辑时,将会发现代码的层级会逐渐加
- 在.NET中有三种计时器:一、 System.Windows.Forms命名空间下的Timer控件,和所在的Form属于同一个线程。Time
- 本文为个人理解,不保证完全正确。官方文档中将双冒号的用法分为4类,按照我的个人理解可以分成2类来使用。官方文档官方文档中将双冒号的用法分为了
- 第1类:嵌套模式package day14;import java.io.FileInputStream;import java.io.Fi
- 思路:首先进入登录界面,输入账号和密码后登陆到主界面,在主界面通过点击按钮发送一条强制下线的广播,广播接收者收到广播后重新进入登陆界面。新建
- 一、概述IDEA自带的注释模板一般都很简单,然而我们在写代码的时候喜欢把类注释和文档注释写在代码里,既方便自己看所有的参数,也便于以后维护代
- 目录前言1.设计模式:单例模式1.1 使用时分配,1.2 声明时实例化1.3 双检锁1.4 .net 特性保证的线程安全1.5 使用DI依赖
- 什么是AOPAOP是 Aspect Oriented Programming 的缩写,即面向切面编程,和平常遇到的面向对象OOP编程不一样的
- 一、ProgressBar1. 常用类型1.1 不确定式圆形进度条style="@android:style/Widget.Hol
- Android:AIDL和远程Service调用本讲的内容,理解起来很难,也许你看了很多资料也看不明白,但是用起来缺简单的要命。所以我们干脆
- 工厂模式和简单工厂有什么区别。废话不多说,对比第一篇例子应该很清楚能看出来。优点: 工厂模式弥补了简单工厂模式中违背开放-封闭原则,又保持了
- CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。
- 废话不多说,直接上代码,小伙伴们仔细看 * 释吧。/*简单的复制 剪切 粘贴 功能 操作: &nb
- 要求:取指定目录下面的所有图片,以表格的型式展示并显示该图片的相对路径。服务端代码: public partial class ViewIc
- 定义注解也叫原数据,它是JDK1.5及之后版本引入的一个特性,它可以声明在类、方法、变量等前面,用来对这些元素进行说明。作用生成文档:通过代
- 今天在群里看见有人问了这个问题,那就把我自己总结的知识拿出来与大家分享一下吧..当然可能还有什么不对的地方,希望指出:***msbase.j
- 背景:SpringMVC如何响应json格式的数据?技术实现方式1:在Controller使用@RestController注解方式2:在C
- using System; using System.Collections.Generic; using
- 有些中级开发小伙伴还是搞不太明白在继承父类以及不同场景实例化的情况下,父类和子类的各种方法的执行顺序到底是什么,下面通过场景的举例来重新认识