Collector(三)

  本文承接Collector(二),继续介绍其他的收集器。

  图1是Lucene常用的几个Collector:

图1:

TopDocsCollector

TopFieldCollector

  Collector(二)的文章中,我们介绍了TopScoreDocCollector收集器以及它的两个子类SimpleTopScoreDocCollector、PagingTopScoreDocCollector,它们的排序规则是"先打分,后文档号",TopFieldCollector的排序规则是“先域比较(FieldComparator),后文档号”。

  我们先通过例子来介绍如何使用TopFieldCollector排序的例子,随后介绍排序的原理。

  本人业务中常用的排序域有SortedNumericSortField、SortedSetSortField,其他的排序域可以看SortField类以及子类,在搜索阶段如果使用了域排序,那么Lucene默认使用TopFieldCollector来实现排序。

例子

SortedNumericSortField

图2:

图3:

SortedSetSortField

图4:

图5:

  如何在搜索阶段选择排序域值:

  SortedNumericSortField也可以在索引阶段设置多个具有相同域名的不同域值,其用法跟SortedSetSortField一致,不赘述。

  接下来我们根据过滤(filtering)规则,我们接着介绍TopFieldCollector的两个子类:

SimpleFieldCollector

  SimpleFieldCollector的collect(int doc)方法的流程图:

图6:

点击查看大图

预备知识

IndexWriterConfig.IndexSort(Sort sort)方法

  在初始化IndexWriter对象时,我们需要提供一个IndexWriterConfig对象作为构造IndexWriter对象的参数,IndexWriterConfig提供了一个setIndexSort(Sort sort)的方法,该方法用来在索引期间按照参数Sort对象提供的排序规则对一个段内的文档进行排序,如果该排序规则跟搜索期间提供的排序规则(例如图3的排序规则)是一样的,那么很明显Collector收到的那些满足搜索条件的文档集合已经是有序的(因为Collecter依次收到的文档号是从小到大有序的,而这个顺序描述了文档之间的顺序关系,下文会详细介绍)。

  以下是一段进阶知识,需要看过文档的增删改以及文档提交之flush系列文章才能理解,看不懂可以跳过

  索引期间,图7

  搜索期间,替换下图3的内容,使得图2中的例子中 搜索期间跟查询期间的有一样的排序规则,图8

图9:

  由图9可以知道,Collector还是依次收到 0 ~ 4的文档号,但是对应的文档号已经发生了变化,因为这些文档在索引期间已经根据域名为"sortByNumber"的SortedNumerricSortField域的域值排好序了。

  极其重要)尽管在索引期间已经对段内的文档进行了排序,实际上文档0~文档4在段内的真实文档号依旧是:0、1、2、3,只是通过图9中的数组实现了映射关系,故给出下图:

图10:

  图10中通过数组实现的映射关系即Sorter.DocMap对象sortMap,在flush阶段,生成sortMap(见文档提交之flush(三))。

结语

  TopFieldCollector相比较Collector(二)中TopScoreDocCollector,尽管他们都是TopDocsCollector的子类,由于存在索引期间的排序机制,使得TopFieldCollector的collect(int doc)的流程更加复杂,当然带来了更好的查询性能,至于如何能提高查询性能,由于篇幅原因,会在下一篇介绍图6的collect(int doc)的流程中展开介绍。

点击下载附件