首发于ES & Lucene

lucene 数据结构之 IndexedDISI

IndexedDISI (indexed of document in segment iterator),是基于磁盘的数据结构,并实现了 DocIdSetIterator。
作用:作为 doc 的存储结构并实现了迭代功能,每次迭代获取的是文档在 segment 中的 index,即段内索引。

存储结构

代码:点击进入

IndexedDISI 划分为 block 存储,便于 doc 的查找。一个 block 最多存 65536 个 doc。比如文档号 0~65535 落到第一个 block,文档号 65536~xxx 落到第二个 block,以此类推。这里顺便回顾下 NumericDocValues 中的 docsWithField,其实就是 IndexedDISI 结构,如下:

IndexedDISI

Block

出于存储空间和性能考虑,按稠密度将 Block 分为三种,如下:

  • ALL

这种情况指的是,Block 中 65536 个 doc 都存在

  • DENSE

这种情况指的是,Block 中的文档数为 [4096, 65536)

  • SPARSE

这种情况指的是,Block 中的文档数量为 [1, 4096)

那么对于上述三种情况,Block 分别是如何组织的呢?下面逐一介绍。

ALL

稠密度为 ALL 代表 Block 文档数填满了,那么没必要存储具体的文档号,Block 存储结构如下:

Block_ALL

blockid

当前 Block 的编号,编号由 0 开始递增。通过 blockid 便能够计算出当前 Block 的起始文档号,如 blockid 为 1 时,起始文档号为 1 << 16。

numberOfDoc

当前 Block 中存储的 doc 数量,结合 blockid 即可得知 Block 中所有文档号。

DENSE

稠密度为密集状态时,Block 使用 bitmap 来存储文档号,结构如下:

Block_DENSE

word

一个 word 其实就是一个 long 类型,多个 word 构成一个 bitmap,用来存储 Block 的 doc。一个 word 占 8 字节,可以存 64 个 doc,而一个 Block 可以存储 65536 个 doc,因此,这里的 word 数量为 65535 / 64 = 1024。可以看出,采用 bitmap 存储时,空间大小固定为 8KB。

ranks rank 指的是 Block 中一批连续的 bit 位(默认是 1 << 9,即 512 个位),一个 Block 被划分为多个 rank,这里每个 rank 存储值 bitCount 代表当前 rank 之前的所有 rank 中有效位为 1 的数量的累加值,即文档数。ranks 的作用是:查询 doc 时,可以快速计算文档数。

这里举个例子,假设 word0 ~ word7 有 500 个文档,word8 ~ word15 有 400 个文档,word16 ~ word23 有 300 个文档,其他 word 忽略,那么 ranks 构成如下所示:

ranks

SPARSE

稠密度为稀疏状态时,block 存储结构如下:

Block_SPARSE

稀疏 Block 的文档数为 [1, 4096),由于文档数较少,直接存 docid 即可。这里直接用 short 来存储 docid,这里为什么能用 short 来存储 docid 呢?由于通过 blockid 可以计算出该 Block 的起始 docid,因此,这里只需要存储 doc 在 block 内的相对 id 即可,比如文档号 65538 所在的 Block 编码为 1,那么存在 Block 中的 id 为 2(65538 - 1 << 16)。

JumpTable

如图 IndexedDISI,JumpTable 由多个 Entry 构成,Entry 和 Block 一一对应,每个 Entry 主要描述对应 Block 的两个信息:

  • offset: Block 在 dvd 中的偏移,加速定位查找
  • index: 段内索引,代表 Block 的第一个有效文档号在 segment 内的偏移,加快计算当前 Block 要查找的 doc 对应的段内索引

offset 的作用比较好理解,不必多说。对于 index 这里举个例子,假设 block0 包含文档号 1~10,block1 包含文档号 66666~88888。那么 Entry0 的 index 为 0,Entry1 的 index 为 10,Entry2 的 index 为22232。

总结

本文主要介绍了数据结构 IndexedDISI,后续将会在讲解 DocValues 写入源码时,对 IndexedDISI 的构建源码进行解析,同时结合本文可以更容易地理解源码逻辑。

编辑于 2023-05-28 14:30・IP 属地四川