lucene5.3.1的排序是怎么实现的?

Posted 中中

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lucene5.3.1的排序是怎么实现的?相关的知识,希望对你有一定的参考价值。

排序有两种方式,在只有一个排序字段的情况下,分别看下这两种方式的实现方式。

1.在索引阶段生成排序索引(dvm,dvd):

在添加正常的字段后再添加一个该字段的SortedDocValuesField到document,即可按这个字段排序。

SortedDocValuesField pathField = new SortedDocValuesField("path", new BytesRef(f.getName().getBytes()));
doc.add(pathField);
TextField tf=new TextField("path", f.getName(), Field.Store.YES);
doc.add(tf);

生成索引后,可以发现多了两个文件_0_Lucene50_0.dvd与_0_Lucene50_0.dvm,这两就是就是排序相关文件了。然后查询时用普通的IndexReader ir = DirectoryReader.open方式。再到下图的地方打断点,可以看到,在加载索引文件时候就执行了readSortedField方法,读出的数据就是排序后的doc集合了。


dvm是dvd文件的元数据,所以变量名叫meta。从这个文件可以找到在dvd文件中存docId的下标为119,如下图:

lucene5.3.1的排序是怎么实现的?


我用程序在119这个位置只发现了一个字节值为64,这个怎么表示两个docId呢?虽然我还看懂算法,但我找到了位置,如下:

lucene5.3.1的排序是怎么实现的?


2.在查询阶段排序(uninvert):

读取数据的时候用UninvertingReader包装一下,这样在查询时就会先把字段及其terms,terms对应的doc列表读取来,而terms已经是排序好的,就按这个再排一下doc列表即可。

DirectoryReader ir = UninvertingReader.wrap(DirectoryReader.open(FSDirectory.open(new File(indexDir).toPath())), Collections.singletonMap("path", Type.SORTED_SET_BINARY));
如下图:

lucene5.3.1的排序是怎么实现的?

在这个DocTermOrds.uninvert方法中,解析原索引文件后存到了如下结构:

lucene5.3.1的排序是怎么实现的?

reader.maxDoc()是从si文件中读出maxDoc值,就是最大doc编号。DocTermOrds.index存的是id的code。uninvert过程如下:

lucene5.3.1的排序是怎么实现的?

在查询时根据tim中的terms知道了有那些doc,但还不知道这些doc的顺序,所以依次执行如下函数得到顺序。

lucene5.3.1的排序是怎么实现的?

在termsIndex的getOrd方法中,先得到当前doc的code,就是前面uninvert生成的DocTermOrds.index,这个code在下图的read方法中会填充buffer。

lucene5.3.1的排序是怎么实现的?

再通过DocTermOrds$Iterator.nextOrd方法取出刚填充的code就是doc的顺序了。


而我调试solr源码时发现,solr5.3.1用的是第二种方式(uninvert),这可能会影响一点查询效率。由于solr的索引文件用了复合模式,我暂不知道里面有没有dvm,dvd文件。测试发现,如果索引用了dvd/dvm文件,即使查询代码用了UninvertingReader,也不会执行uninvert,而是在初始化时就加载了排序的dvd/dvm文件。




以上是关于lucene5.3.1的排序是怎么实现的?的主要内容,如果未能解决你的问题,请参考以下文章

Lucene —— 搜索结果高亮显示

QT中QTableView是怎么实现数字的排序

TreeSet集合的底层是怎么实现元素排序的

python怎么实现数组排序

VC ListCtrl 列表 单击排序怎么实现

redis zset怎么实现多条件排序