DocValue其实就是Lucene中的正向索引概念,为什么有倒排索引还需要正排索引,倒排索引是解决检索的性能问题的话,而正排索引则是解决搜索字段排名问题。

其实在4.0之前,Lucene也有FieldCache的概念,将文档的字段值放入内存,同样是根据docid取得某个字段上的值,但是为什么有产生了DocValues呢?

Lucene的FieldCache是怎么构建出来的呢,答案是从倒排索引反推出来,但是这种效率极低的,当索引足够大的时候,从倒排索引构建FieldCache是非常耗时的,所以在4.0之后就产生了Docvalues正向索引的存储结构。

Docvalues是面向列存储的,被标记为Docvalues的Field在建索引的时候,会将字段值存储到磁盘上,即索引目录中每个Segment中的如下格式文件:

  • .dvd,元数据文件
  • .dvm,meta文件,可以认为是正向索引数据的索引,保存了每条记录的起始位置、长度以及数据格式

何为列存储,众所周知,大部分存储系统都是采用append的模式记录数据的,如更新、删除还少是找到之前数据的位置编辑的,这样的代价太大了,而基于append这种模式,会有两种选择:

  • 行存储,也就是先将一个文档的所有字段值写入,再继续写入下一个文档
  • 列存储,先将固定写某个字段,即将所有文档的某个字段写入,再去下个字段

下图给出行列存储的结构:
行列存储

对于这两种模式,其实各有优劣,主要看场景,举例来说,假如我们想连续读取doc1、doc2、doc3...在字段F1上的值,那么显然基于列存储是最优的,因为同一个字段是在连续存储,在取值时,大大减少了磁盘寻址时间。而如果我们存在大量按文档读取的情形,那么基于行存储是合适的。

因为Docvalues更偏向于key-value结构的使用方式,所以无论write还是read其实采用列存储的方式都是合适的,在索引没有被commit前,Docvalues数据都是写入内存的,直到commit动作到来后,才会落盘。

在Lucene中提供了几种DocvaluesFormat:

  • Lucene54DocValuesFormat,默认的
  • MemoryDocValuesFormat
  • DirectDocValuesFormat