使用Java的Lucene搜索工具对检索结果进行分组和分页
使用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;
上一篇: 【Python】第五节-字典\集合