lucene系列(五)索引格式之fdm文件

·  阅读 204

本文使用 Lucene 代码版本:8.7.0

前言

首先学习一下 lucene 的索引文件结构。本文介绍 Field 相关信息的存储文件格式。

当你在写入 field 信息时,如果像下面这样,指定了 Stored. 也就是希望 lucene 能够保存你的原始 Field 信息,那么就会生成三个文件 .fdt .fdm .fdx.

2021-01-23-18-00-42

其中

  • .fdt 文件保存了原始的 field 信息
  • .fdx 文件保存了一些帮助读取 fdt 的索引信息
  • .fdm 文件保存了一些基本的元数据,也包括一些辅助读取 fdx 文件的信息。

本文首先介绍 fdm 的文件格式,及学习一下其在 Lucene8.7.0 中的写入相关代码。

.fdm 文件整体结构

2021-01-23-18-05-13

  • IndexHeader 索引文件头

lucene 对于索引文件,会写一个文件头,来标识一些基本的数据。

2021-01-23-18-35-00

包含:

  • CodecHeader: 一个编码的 Header.
  • SegmentID: 当前 Segment 的 ID, 随机生成的 16 位字符串
  • SegmentSuffix: 当前 Segment 的后缀
  • Magic: 一个魔法数字,永远是:0x3fd76c17.
  • CodecName: 当前编码的名字,比如对于当前的 fdm 文件时:"Lucene85FieldsIndexMeta"
  • Version: 一个内部的版本号,不是 lucene 版本号哦。
  • ChunSize 每个 Chunk 中的 doc 数量
  • Version 版本号
  • NumDocs: doc 数量的总数
  • BlockShift: 控制 chunk 信息写入时的分块,2 ^ blockShift 为一块。
  • totalChunks: 总共有多少个 chunk
  • ChunkDocsNumIndex: 存储每个 chunk 中 doc 数量的内容,在 fdx 文件中的起始偏移位置
  • ChunksDocsNumMeta: fdx 文件中存储 Chunk 中 doc 数量,用到的一些元数据

2021-01-23-18-50-51

在 fdx 文件中,存储每个 chunk 中的 doc 数量时,使用了DirectMonotonicWriter类来进行存储,这个类用来存储单调递增数组,能够进行一些压缩。具体的别的文章中详细说~

为了完成压缩的功能,需要一些数字进行辅助,就是下面这几位咯。

- Min : 通过编码计算的最小值
- AvgInc: 通过编码计算的平均斜率
- ChunDocsNumIndex: 从开始写入到现在,fdx 文件的偏移量
- BitRequired: 所有要写入的数字,最大需要多少位才能存储
复制代码
  • ChunkStartIndex: 存储每个 chunk 数据起始位置数据的起始位置
  • ChunkStartPointMeta: 存储每个 chunk 数据起始位置的一些元数据

在储存每个 chunk 的数据在 fdx 文件中的起始位置的相关数据时,和上面的 chunk 内 doc 数量一样,做了一些压缩~

2021-01-23-18-54-34

- Min : 通过编码计算的最小值
- AvgInc: 通过编码计算的平均斜率
- ChunDocsNumIndex: 从开始写入到现在,fdx 文件的偏移量
- BitRequired: 所有要写入的数字,最大需要多少位才能存储
复制代码
  • StartPointEndPoint: 存储每个 chunk 数据起始位置的数据的结束位置。
  • MaxPoint: fdx 的最大写入位置
  • numDirtyChunks: 脏的 chunk 的数量,当 chunk 并没有到达数量,而是强行进行 finish, 那么相关的 chunk 和 doc 就是 dirty 的。这两个变量记录了一下相关的数量。
  • numDirtyDocs: 脏的 doc 的数量
  • footer: 索引文件的脚部

知其然知其所以然

每个字段,每段数据,是为什么存储,其实我不太知道。目前看的代码还不是很多。

但是我们应该知道,所以我罗列在这里,不知道的后来补上~

数据/字段名内容作用
IndexHeader索引文件 header为了标识一些基础信息,也可以用来做一些文件的验证。
ChunSize每个 chunk 包含多少个 docchunk 是固定大小的,在创建时会初始化,因此可以方便的按 chunk 进行读取,索引等。
Version内部版本号不知道。
NumDocs当前文件的总数计数用。
BlockShift多少 chunk 的数据进行一个 block 存储对 chunk 的数据进行分块存储用
totalChunks总共有多少个 chunk计数用。
ChunkDocsNumIndex存储每个 chunk 中 doc 数量的内容,在 fdx 文件中的起始偏移位置方便读取 fdx 文件
ChunksDocsNumMetafdx 文件中存储 Chunk 中 doc 数量,用到的一些元数据fdx 文件对数据进行压缩,压缩用的一些配合型的数据
Min通过编码计算的最小值记录最小的数字,具体作用在DirectMonotonicWriter中详细解释
AvgInc通过编码计算的平均斜率DirectMonotonicWriter
ChunDocsNumIndex从开始写入到现在,fdx 文件的偏移量DirectMonotonicWriter
BitRequired所有要写入的数字,最大需要多少位才能存储DirectMonotonicWriter
ChunkStartIndex存储每个 chunk 数据起始位置的位置方便读取 fdx 文件
ChunkStartPointMeta存储每个 chunk 数据起始位置的一些元数据同上
StartPointEndPoint存储每个 chunk 数据起始位置的数据的结束位置同上
MaxPointfdx 的最大写入位置同上
numDirtyChunks脏的 chunk 的数量不确定
numDirtyDocs脏的 doc 的数量不确定
footer索引文件的脚部用来表示文件结束,同时里面含有 CRC32 来 check 文件数据是否正确。

相关代码分析

在 8.7.0 版本,对 Field 相关信息的存储在org.apache.lucene.codecs.compressing.CompressingStoredFieldsWriter类中。

首先,在类构造函数中,进行了 fdm 文件的初始化,之后写入了 IndexHeader. 以及chunkSizeVersion.

2021-01-24-00-12-04.

之后在程序不断的添加 Document 过程中,不再写入 fdm 文件,在所有 Document 全部写入之后,会调用 org.apache.lucene.codecs.compressing.CompressingStoredFieldsWriter#finish 方法,在该方法中,写入了部分数据。

2021-01-24-00-14-37

如上图所示,在 1 处写入了 fdm 配合 fdx 文件的一些元数据。 在 2 处写入了numDirtyChunks,numDirtyDocs 及 Footer.

在 1 处,配合 fdx 文件写入了些什么呢?

2021-01-24-00-19-01

在 3 处,写入了numDocs, blockShift, totalChunks, filePoint等信息。这些都是顺序的,和前方的整体格式图一一对应。

比较麻烦的是,在上图中 4 处,在 fdx 文件存储所有 chunk 中 doc 数量时,应用了DirectMonotonicWriter 类来进行存储,该类的具体实现可以阅读延伸阅读中的文章。DirectMonotonicWriter 源码分析

该类大致做了什么呢?

  • 所有 chunk 的 doc 数量。
  • 所有 chunk 具体信息存储的 point.

这两个数组都是单调递增的,因此DirectMonotonicWriter类就是专门用来存储单调递增数组的。 根据单调递增这个因素,对传入的 int 数组进行了压缩,压缩中用到了几个参数,在之后复原数据时需要。那就是Min,AvgInc,Offset,BitRequired. 这里使用了 fdm 文件来存储这几个参数而已。

延伸阅读

DirectMonotonicWriter类的原理解析。具体文章还没写哈哈哈。

参考文章

www.amazingkoala.com.cn/Lucene/suoy…


完。

以上皆为个人所思所得,如有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文链接。

联系邮箱:huyanshi2580@gmail.com

更多学习笔记见个人博客或关注微信公众号 < 呼延十 >------>呼延十

分类:
后端
标签: