lucene的分组(group by)

原文地址:http://xtuhcy.iteye.com/blog/1143440

 

最近在优化搜索服务,以前的搜索服务十分简单,现在需要增加查询结果分组统计的功能,以提高用户体验。

g了一番,有以下几个主要的实现方式:

1、利用search中的collect,自己实现一个collect输出分组统计结果;

2、一个开源的lucene插件bobo browser

3、lucnen3.2后有个grouping模块

最后我选择了grouping这个模块来实现

grouping模块有2种方法实现,2次遍历法和1次遍历法。1次遍历法是在lucene3.3之后才开始提供。

1次遍历法效率很高,但是需要在索引时添加特殊的标志:

To use the single-pass BlockGroupingCollector, first, at indexing time, you must ensure all docs in each group are added as a block, and you have some way to find the last document of each group. One simple way to do this is to add a marker binary field:

网站访问量目前还很小,又不想重新建索引,于是还是采用了2次遍历法。2次遍历的第一次遍历是把分组拿出来,如果您只需要分组,不需要各个分组的数量,可以一次遍历即可。第二次遍历是把各个分组的搜索结果拿出来,当然也就能知道各个分组的数量。

2次遍历法由于需要经过2次搜索效率较低,因此引入了一个cache机制,CachingCollector。这样在第二次遍历是就可以直接读内存了。

代码片段如下:

public Map<String, Integer> groupBy(Query query, String field, int topCount) {
  Map<String, Integer> map = new HashMap<String, Integer>();
 
  long begin = System.currentTimeMillis();
  int topNGroups = topCount;
  int groupOffset = 0;
  int maxDocsPerGroup = 100;
  int withinGroupOffset = 0;
  try {
   TermFirstPassGroupingCollector c1 = new TermFirstPassGroupingCollector(field, Sort.RELEVANCE, topNGroups);
   boolean cacheScores = true;
   double maxCacheRAMMB = 4.0;
   CachingCollector cachedCollector = CachingCollector.create(c1, cacheScores, maxCacheRAMMB);
   indexSearcher.search(query, cachedCollector);
   Collection<SearchGroup<String>> topGroups = c1.getTopGroups(groupOffset, true);
   if (topGroups == null) {
    return null;
   }
   TermSecondPassGroupingCollector c2 = new TermSecondPassGroupingCollector(field, topGroups, Sort.RELEVANCE, Sort.RELEVANCE, maxDocsPerGroup, true, true, true);
   if (cachedCollector.isCached()) {
    // Cache fit within maxCacheRAMMB, so we can replay it:
    cachedCollector.replay(c2);
   } else {
       // Cache was too large; must re-execute query:
    indexSearcher.search(query, c2);
   }
  
   TopGroups<String> tg = c2.getTopGroups(withinGroupOffset);
   GroupDocs<String>[] gds = tg.groups;
   for(GroupDocs<String> gd : gds) {
    map.put(gd.groupValue, gd.totalHits);
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
  long end = System.currentTimeMillis();
  System.out.println("group by time :" + (end - begin) + "ms");
  return map;
}

几个参数说明:

  • groupField: 分组域
  • groupSort: 分组排序
  • topNGroups: 最大分组数
  • groupOffset: 分组分页用
  • withinGroupSort: 组内结果排序
  • maxDocsPerGroup: 每个分组的最多结果数
  • withinGroupOffset: 组内分页用

 

评论

 

2 楼    wyyl1    2011-12-07      引用
非常感谢!
今日搜索了,lucene的解决方法,你说的这个可以用。但是只用一次循环的那个方法,我试了好长时间没有搞定!有时间希望交流一下,循环一次的那个方法。

我使用的是lucene3.5.0版本的组件
就是参考http://lucene.apache.org/java/3_5_0/api/contrib-grouping/org/apache/lucene/search/grouping/package-summary.html
循环一次的没有成功

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
注:下文中的 *** 代表文件名中的组件名称。 # 包含: 中文-英文对照文档:【***-javadoc-API文档-中文(简体)-英语-对照版.zip】 jar包下载地址:【***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: 中文-英文对照文档,中英对照文档,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【***.jar中文文档.zip】,再解压其中的 【***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·本文档为双语同时展示,一行原文、一行译文,可逐行对照,避免了原文/译文来回切换的麻烦; ·有原文可参照,不再担心翻译偏差误导; ·边学技术、边学英语。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值