Lucene 源码系列——tvx tvd 索引文件

当设置了 TermVector 的域生成了倒排表以后,将文档的词向量信息写到。tvx(vector_index)跟。tvd(vector_data)文件中。

数据结构

.tvd

图 1:
1.png

PackedIntsVersion

PackedIntsVersion 描述了压缩使用的方式,当前版本中是 VERSION_MONOTONIC_WITHOUT_ZIGZAG。

ChunkSize

ChunkSize 用来在压缩存储域值信息的方式,后面会详细介绍。

Chunk

图 2:
2.png

在文档数达到 128 篇之前,如果这些文档中的所有存储域的域值长度达到 4096,或者文档数达到 128 篇,那么就使得这些文档的信息生成一个 Chunk。

DocBase

DocBase 是 chunk 中第一个文档的文档号。

ChunkDocs

chunk 中包含的文档个数。

NumFields

NumFields 记录了每篇文档中存储域的个数 NumField,根据 chunk 中的个文档数 chunkDocs,分为不同的情况:

chunkDocs == 1

图 3:
3.png

直接记录该片文档的存储域的个数 NumField。

chunkDocs ≥ 1

图 4:
4.png

记录 chunk 中的每一篇文档的存储域的个数,使用 PackedInts 存储。

FieldNums

FieldNums 中存储当前 chunk 中域的种类,根据域的编号来获得 域的种类,根据域的种类个数分为不用的情况:

(域的种类 - 1) ≤ 7

图 5:
5.png

token

token 是一个组合值,并且大小是一个字节:

  • numDistinctFields:当前 chunk 中的域的种类
  • bitsRequired:存储每一个域的编号需要最少 bit 位个数
  • 左移 5 位描述了 bitsRequired 最多可以是 31
  • 由于一个字节的低五位被用来描述 bitsRequired,所以还剩余 3 个字节可以用来表示 numDistinctFields,所以 numDistinctFields ≤ 7 时可以跟 bitsRequired 使用一个字节存储。
PackedIntsValue

把所有的域的编号用 PackedInts 存储。

(域的种类 - 1) > 7

图 6:
6.png

token

token 是一个组合值,并且大小是一个字节:



  • bitsRequired:存储每一个域的编号需要最少 bit 位个数
  • numDistinctFields 的值大于 7,那么在 token 中就是 (7 << 5 ) | bitsRequired
  • numDistinctFields - 0x07:存储剩余的差值

FieldNumOffs

图 7:
7.png

FieldNumOffs 中存放了 chunk 中每一篇文档包含的所有域的编号的索引,并且使用 PackedInts 存储,该索引其实就是 fieldNums[]数组的下标值,fieldNums[]数组的数组元素是 chunk 中的域的编号,数组元素个数是域的种类。通过这种方式使得不直接存储域的编号,因为域的编号可能跨度很大,并且值很大,那就需要更大的存储空间,而存储下标值就可以解决这个问题。
图 8:
8.png

上图中有 4 个域的编号,如果直接存储域的编号,那么需要 3 (8) + 8 (255) + 2 (2) + 2 (3) = 15 个 bit 位,如存储索引即小标志时,那么需要 1 (0) + 1 (1) + 2 (2) + 2 (3) = 6 个 bit 位。

Flags

Flags 用来描述域是否存放位置 position、偏移 offset、负载 payload 信息,flag 的值可以是下面 3 个值的组合:

  • 0x01:包含位置 position 信息
  • 0x02:包含偏移 offset 信息
  • 0x04:包含负载 payload 信息

比如说 flag = 3,二进制即 0b00000011,即包含位置跟偏移信息。
根据相同域名在不同的文档中是否有相同的 Flag 分为不同的情况:

相同的域名有相同的 flag

图 9:
9.png

对于某个域名来说,无论它在哪个文档中都记录相同的 flag 信息,所以只要每种域名记录一次即可,并且用 PackedInts 存储,固定值 0 为标志位,在读取阶段用来区分 Flags 的不同数据结构。

相同的域名有不相同的 flag

图 10:
10.png

对于一个域名来说,它在不同文档中的 flag 可能不一样,所以必须记录所有文档中的所有域的 flag,并且用 PackedInts 存储,固定值 1ss 为标志位,在读取阶段用来区分 Flags 的不同数据结构。

TermData

TermData 记录了域值信息,下文中提及的 term 是指域值通过分词器获得一个或多个 token。
图 11:
11.png

NumTerms

NumTerms 描述了每一篇文档的每一个域包含的 term 个数,使用 PackedInts 存储。

TermLengths

TermLengths 描述了每一篇文档的每一个域中的每一个 term 的长度,使用 PackedInts 存储。

TermFreqs

TermFreqs 描述了每一篇文档的每一个域中的每一个 term 在当前文档中的词频,使用 PackedInts 存储。

Positions

Positions 描述了每一篇文档的每一个域中的每一个 term 在当前文档中的所有位置 position 信息,使用 PackedInts 存储。

StartOffset

StartOffset 描述了每一篇文档的每一个域中的每一个 term 的 startoffset,使用 PackedInts 存储。

Lengths

Lengths 描述了每一篇文档的每一个域中的每一个 term 的偏移长度,使用 PackedInts 存储。

TermAndPayloads

使用 LZ4 算法存储每一篇文档的每一个域中的每一个 term 值跟 payload(如果有的话)。

ChunkCount

.tvd 文件中 chunk 的个数。

.tvd 整体数据结构

图 12:
12.png

.tvx

.tvx 跟.fdx 的生成代码在源码中是一模一样的,所以不赘述了。


本文地址:https://www.6aiq.com/article/1586738745210
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出