lucene的分组(group by)

转载 2012年03月23日 17:44:31

原文地址: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
循环一次的没有成功

 

相关文章推荐

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

lucene实现分组统计的方法

转:http://www.cnblogs.com/huangfox/archive/2012/07/10/2584750.html http://blog.163.com/liugangc@126/...

一步一步跟我学习lucene(12)---lucene搜索之分组处理group查询

grouping介绍 我们在做lucene搜索的时候,可能会用到对某个条件的数据进行统计,比如统计有多少个省份,在sql查询中我们可以用distinct来完成类似的功能,也可以用group by来对查...

[Lucene高性能] Lucene中分组统计(GroupBy)及去重(Distinct)性能在数量级上提升解决方案

所谓分组统计,就是类似sql里group by的功能。在solr里,这个功能称为faceting。lucene本身不支持分组统计,不过可以使用fieldCache来实现分组统计功能,而且也有很好的性能...

Lucene聚类分组统计功能(grouping)

在搜索的项目中,我们经常有对搜索结果进行分组或对字段进行压缩的需求。之前的文章提到这个功能已经添加到solr中并成为用户一个非常需要的特性。最近结果分组被作为一个扩展包加入到lucene3.1中,而在...

【Lucene学习笔记】索引的增删改查与查看工具

一、基本增删改查 二、索引查看工具Luke 三、关于Lucene4.10.2中的FieldType 而在最新的4.10.2版本中是由以下这些参数来与之对应的: TextField.TYPE_STORE...

用Hibernate实现领域对象的自定义字段

导言 在开发企业级业务应用(企业规模)时,客户往往要求在不修改系统源代码的情况下对应用对象模型的扩展性提供支持。利用可扩展域模型可以实现新功能的开发,而不需要额外的精力和成本 应用的使用周期将...

使用Group by分组统计.rar

  • 2010年07月02日 13:12
  • 43KB
  • 下载

MySQL对数据表进行分组查询(GROUP BY)

MySQL对数据表进行分组查询(GROUP BY) GROUP BY关键字可以将查询结果按照某个字段或多个字段进行分组。字段中值相等的为一组。基本的语法格式如下: GROUP BY 属性名 [...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:lucene的分组(group by)
举报原因:
原因补充:

(最多只允许输入30个字)