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

2021-02-02 14:36:11 浏览数 (1)

本文使用Lucene代码版本: 8.7.0

前言

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

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

其中

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

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

.fdm文件整体结构

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

包含:

  • 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数量, 用到的一些元数据

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

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

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

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

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

知其然知其所以然

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

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

数据/字段名

内容

作用

IndexHeader

索引文件header

为了标识一些基础信息,也可以用来做一些文件的验证.

ChunSize

每个chunk包含多少个doc

chunk是固定大小的,在创建时会初始化,因此可以方便的按chunk进行读取,索引等.

Version

内部版本号

不知道.

NumDocs

当前文件的总数

计数用.

BlockShift

多少chunk的数据进行一个block存储

对chunk的数据进行分块存储用

totalChunks

总共有多少个chunk

计数用.

ChunkDocsNumIndex

存储每个chunk中doc数量的内容, 在fdx文件中的起始偏移位置

方便读取fdx文件

ChunksDocsNumMeta

fdx文件中存储Chunk中doc数量, 用到的一些元数据

fdx文件对数据进行压缩,压缩用的一些配合型的数据

Min

通过编码计算的最小值

记录最小的数字,具体作用在DirectMonotonicWriter中详细解释

AvgInc

通过编码计算的平均斜率

DirectMonotonicWriter

ChunDocsNumIndex

从开始写入到现在, fdx文件的偏移量

DirectMonotonicWriter

BitRequired

所有要写入的数字, 最大需要多少位才能存储

DirectMonotonicWriter

ChunkStartIndex

存储每个chunk数据起始位置的位置

方便读取fdx文件

ChunkStartPointMeta

存储每个chunk数据起始位置的一些元数据

同上

StartPointEndPoint

存储每个chunk数据起始位置的数据的结束位置

同上

MaxPoint

fdx的最大写入位置

同上

numDirtyChunks

脏的chunk的数量

不确定

numDirtyDocs

脏的doc的数量

不确定

footer

索引文件的脚部

用来表示文件结束,同时里面含有CRC32来check文件数据是否正确.

相关代码分析

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

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

.

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

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

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

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

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

该类大致做了什么呢?

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

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

延伸阅读

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

参考文章

https://www.amazingkoala.com.cn/Lucene/suoyinwenjian/2020/1013/169.html

完。

联系我

最后,欢迎关注我的个人公众号【 呼延十 】,会不定期更新很多后端工程师的学习笔记。 也欢迎直接公众号私信或者邮箱联系我,一定知无不言,言无不尽。

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

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

联系邮箱:huyanshi2580@gmail.com

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

var gitment = new Gitment({ id: 'Lucene系列(五)索引格式之fdm文件', // 可选。默认为 location.href owner: 'hublanker', repo: 'blog', oauth: { client_id: '2297651c181f632a31db', client_secret: 'a62f60d8da404586acc965a2ba6a6da9f053703b', }, }) gitment.render('container')


  • Previous Lucene系列(四)directmonotonicwriter源码分析
  • Next Lucene系列(六)索引格式之fdt文件

0 人点赞