自己动手写分布式搜索引擎
上QQ阅读APP看书,第一时间看更新

3.5.3 文档值

FieldCache是索引的正向视图,也就是文档编号→值的视图。FieldCache需要从倒排索引中解析出值,如图3-16所示。

图3-16 从倒排索引解析出值

可以轻松地使用FieldCache加载某一特定列的本地值数组。例如,如果每个文档有一个字段为weight,也就是PageRank值列。

        Field f = new Field("weight", doc.pageRank ,
              Field.Store.YES, Field.Index.UN_TOKENIZED,
              Field.TermVector.NO);

则可以这样得到所有文档的权重:

        float[] weights = FieldCache.DEFAULT.getFloats(reader, "weight");

然后,每当需要知道一个文档的权重值时,只需参考weights[docID]。

FieldCache支持许多本地类型:字节、短整型、长整型、浮点数、双精度和StringIndex类,其中包括字符串值的排序顺序。

第一次访问给定的reader和列的field cache时,将访问所有文档的值,并作为一个独立的大数组加载到内存中。值记录到一个以reader实例和列名作为键的内部缓存中。因为要从倒排索引中解析出值,所以对大的索引来说,加载过程很耗时。

IndexDocValues不需要从倒排索引中解析出值,因为在建立索引时提供了一个文档到值的映射。IndexDocValues允许在文档索引时,可以更多地控制数据。每一个普通的Lucene列接收一个类型的值,以列的方式存储。通过ValueType指定某个列的IndexDocValues类型,例如长整型、浮点型或者字节数组。

对整数类型,IndexDocValues提供字节对齐的变体,如8, 16, 32和64位,以及压缩的PackedInts。对于浮点值,当前只提供float 32和float 64。但是对于字节数组值,IndexDocValues提供更灵活的存取方式。

可以指定值是否有固定或可变的长度,这些值是否应直接存储,或以取消引用的方式存储,这样在不同值的数很少的情况下可以得到良好的压缩。

因为不需要从倒排索引中解倒排或者解析值,所以IndexDocValues的加载速度很快。

FieldCache只能完全位于内存中,而IndexDocValues可以完全在内存或者位于硬盘。IndexDocValues提供同样的随机读出接口。

读出数据的性能依赖于值的类型。如果选择使用PackedInts压缩整数,就要付出代价。但是如果选择32位对齐的变体,则就好像Java NIO ByteBuffers一样访问底层数组。通过Source.getArray()方法访问数据。

        IndexReader r = IndexReader.open(w, true);
        DocValues docValues = MultiDocValues.getDocValues(r, field);
        Source source = docValues.getSource();


        byte[] values = (byte[]) source.getArray();

有很多应用可以受益于IndexDocValues,例如灵活的评分、分类统计、排序、合并和结果分组这样的搜索功能。

一般来说,当有像排序、分类统计和分组结果这样的功能要实现时,通常需要额外的专用列。以作者列为例,可以为了全文检索而对这个列分词,但这可能会导致分类统计或分组结果出现意外。然而,只需简单地添加一个非分词列就能解决这个问题。非分词列往往用facet_author这样的前缀命名。

IndexDocValues是不分词的,所以可以简单地增加一个同名的IndexDocValuesField来达到和额外列同样的效果。使用IndexDocValues后,就能用更少的逻辑列实现同样的功能。

默认Lucene使用FieldCache,除非声明SortField.setUseIndexValues(boolean)。

        IndexSearcher searcher = new IndexSearcher(...);
        SortField field = new SortField("myField", SortField.Type.STRING);
        field.setUseIndexValues(true); //使用IndexValues实现排序
        Sort sort = new Sort(field);
        TopDocs topDocs = searcher.search(query, sort);