当前位置: 移动技术网 > IT编程>开发语言>Java > 使用Java的Lucene搜索工具对检索结果进行分组和分页

使用Java的Lucene搜索工具对检索结果进行分组和分页

2019年07月22日  | 移动技术网IT编程  | 我要评论
使用groupingsearch对搜索结果进行分组 package org.apache.lucene.search.grouping description 这个模块

使用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.测试结果:

20163684827254.png (1168×355)

两种分页方式
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提供了五个重载方法,可以根据需要使用

20163684904821.png (1012×281)

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;

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网