在前几篇索引文件的读取的系列文章中,我们介绍索引文件tim&&tip的读取时机点时说到,在生成StandardDirectoryReader对象期间,会生成SegmentReader对象,该对象中的StoredFieldsReader信息描述了索引文件fdx&&fdt&&fdm中所有域的索引信息,故我们从本篇文章开始介绍索引文件fdx&&fdt&&fdm的读取。

StoredFieldsReader

  在生成StandardDirectoryReader阶段,就已经开始读取索引文件fdx&&fdt&&fdm实现一些初始化,为随后的搜索阶段做准备,读取后的信息用StoredFieldsReader来描述。

.fdm

图1:

  .fdm文件中存储了元数据,即描述存储域数据的信息,它包含的所有数据将被完整的读入到内存中。

.fdx

图2:

  通过索引文件.fdm中的StartPointsIndex与NumDocsIndex的差值来确定在索引文件.fdx中的一段数据区间,该区间中存储了chunk中的文档数量,同理SPEndPointer与StartPointsIndex的差值确定在索引文件.fdx中的一段数据区间,该区间中存储了每个chunk在索引文件.fdt中的起始读取位置。

  注意的是,在生成StandardDirectoryReader阶段,图2中NumDoc跟StartPoints的字段的值并没有读取到内存中,只是将这两块数据的起始读取位置读取到了内存,相比较在Lucene 8.5.0之前的版本,这种读取方式即所谓的"off-heap"。

off-heap

  在Lucene 8.5.0之前,描述存储域的索引文件为.fdx、.fdt,它们的数据结构完整介绍可以见文章索引文件之fdx&&fdt,本文中中我们暂时只给出索引文件.fdx来介绍"off-heap":

图3:

  在Lucene 8.5.0之前,图3中所有的Block会在生成StandardDirectoryReader阶段就全部读取到内存中,注意的是图3中的DocBases对应图2中NumDocs,命名不同而已,描述的内容是一致。

  此次优化的详细内容可以见这个issue的介绍:https://issues.apache.org/jira/browse/LUCENE-9147 。在文章索引文件的读取(七)之tim&&tip中我们提到,索引文件.tim&&.tii的读取也是用了off-heap,并且在Lucene 8.0.0就早早实现了,为什么在Lucene 8.5.0之后才将存储域的索引文件的读取使用off-heap呢?原因有两点,直接贴出issue原文:

图4:

  图4的大意就是,在terms index(索引文件.tim&&tii)使用了off-heap之后,存储域(stored fields)的索引文件变成了占用内存的大头,但是它没有terms index那样对性能有很大的影响(见文章索引文件的读取(七)之tim&&tip)。

图5:

  图5中的更有意思,Erick Erickson说当在技术层面(technical aspects)无法创新时,那么从内存方面去考虑优化了。

.fdt

图6:

  对于索引文件.fdt,在此阶段通过索引文件.fdm的maxPointer,读取出ChunkCount、DIrtyChunkCount以及ChunkSize、PackedIntsVersion字段而已,也就是说Chunk字段,占用内存最大的数据块,没有被读取到内存中,在搜索阶段才根据条件读取,下文中中会展开介绍。

读取索引文件fdx&&fdt&&fdm的流程图

图7:

准备数据

图8:

  准备数据是全局的文档号。该文档号就是满足搜索条件的文档对应的文档号,例如下图中,ScoreDoc[ ]对象中存放的就是满足查询条件的全局的文档号。

图9:

计算出所属段并转化为段内文档号

图10:

  在生成StandardDirectoryReader对象期间,通过获取每个段中的文档数量,会初始化一个int类型的starts[ ]数组,随后根据这个数据就可以计算出某个全局文档号属于哪一个段。通过读取索引文件.si中的segSize字段来获取每个段中的文档数量,如下所示:

图11:

  我们直接以一个例子来介绍starts[ ]数组:

图12:

  图12的例子,每当count达到1000、3000、20000、100000、结束时就生成一个段,即索引目录中存在5个段。那么对应的starts[]数组如下所示:

图13:

  那么根据starts[ ]数组,通过二分法就能计算出某个全局文档号所属的段了。

  另外starts[ ]数组中的元素还代表了某个段的段内的第一篇文档号,那么将全局文档号与之做减法就获得了段内文档号。注意的是,为了便于介绍,下文中出现的文档号都是段内文档号

文档号是否在BlockState中?

图14:

  BlockState中存储的是当前正在读取的Chunk的一些元数据,至少包含以下的内容:

  • docBase
  • chunkDocs
  • sliced
  • offsets[ ]数组
  • numStoredFields[ ]数组

  这些元数据对应在索引文件中内容如下所示:

图15:

  通过docBase跟chunkDocs就可以判断当前chunk中是否包含某个文档号。

  如果当前chunk中包含某个文档号,那么直接读取该Chunk即可,否则需要重新从.fdt中找到所属chunk(查找过程将在下一篇文中展开),同时更新BlockState,继而获得文档中的存储域信息。从这里我们可以看出,在实际使用过程中,获取存储域的信息时,最好按照全局的文档号的大小依次获取,随机的文档号会导致频繁的更新blockState,也就是需要从索引文件中不断的读取Chunk,即增加了I/O开销。

结语

  基于篇幅,剩余的内容将在下一篇文章中展开。

点击下载附件

Lucene 索引文件的读取(十四)之fdxfdtfdm相关推荐

  1. Lucene 索引文件的读取(十五)之fdxfdtfdm

    本文承接文章索引文件的读取(十四)之fdx&&fdt&&fdm,继续介绍剩余的内容.为了更好的理解下文中的内容,建议先阅读文章DirectMonotonicWriter ...

  2. Lucene 索引文件的合并(四)之kddkdikdm

    本篇文章开始介绍索引文件kdd&kdi&kdm的合并,由于维度值为1和维度值大于等于2的点数据对应的索引文件的合并方式有较大的差异,故我们分开介绍.本篇文章先对维度值为1的情况展开介绍 ...

  3. Lucene 索引文件的载入(一)之fdxfdtfdm

    在文章SegmentReader(一)中,我们介绍了SegmentReader对象,它用于描述一个段中的索引信息,并且说到SegmentReader对象中包含了一个SegmentCoreReaders ...

  4. Lucene 索引文件的生成(二十五)之kddkdikdm

    在系列文章索引文件的生成(Lucene 7.5.0)中,我们介绍了存储维度(见文章Bkd-Tree)值大于等于2的数值类型对应的索引文件的生成过程.对于维度值等于1的情况,其生成过程有少许的不同.为了 ...

  5. Lucene 索引文件的合并(三)之fdxfdtfdm

    本文承接文章索引文件的合并(二)之fdx&&fdt&&fdm,继续介绍剩余的内容,下面先给出索引文件fdx&&fdt&&fdm的合并流程 ...

  6. Lucene 索引文件的生成(二十三)之fdxfdtfdm

    从本篇文章开始介绍用于描述存储域(存储域的概念见文章索引文件之fdx&&fdt&&fdm)的索引文件.fdx..fdt..fdm的生成过程,直接给出流程图: 图1:   ...

  7. Lucene 索引文件之tvdtvxtvm

    在索引(Indexing)阶段,当某个域被设置为需要记录词向量(term vector)信息后,那么随后在flush阶段,该域对应的词向量将被写入到索引文件.tvd&&tvx& ...

  8. Lucene 索引文件之kddkdikdm

    从Lucene8.6.0开始,用于存储点数据(point value)的索引文件由原先的两个索引文件dim&&dii,改为三个索引文件kdd&kdi&kdm.由于生成k ...

  9. SpringBatch 写xml文件(StaxEventItemWriter)用法(十四)

    文章目录 一.pom文件引入需要读取xml文件jar包 二.抽取写xml文件公共writer 三.processor 四.配置写xml文件job 五.执行job 前言:在一些业务场景中,可能需要读取x ...

最新文章

  1. LAS点云查看 转换格式
  2. MySQL中my.cnf解析
  3. 真!长!啊!中国校名最长的学校竟然有55个字!
  4. .Net的类型构造器-static构造函数
  5. 基础知识 + 面试题目 总结 索引页
  6. codevs 1029 遍历问题
  7. GridView.RowCommand 事件
  8. 卸载vs2015社区版本然后装vs2015专业版本出现问题ActivityLog.xml错误
  9. [深度学习] ImageAI库使用笔记
  10. 一位 中国70 后老程序员的 26 个职场感悟
  11. 坎德拉、流明、勒克斯之间的关系
  12. 探秘 Containerd 容器中的 Shim 进程
  13. 量化分析自己的生活——日活统计表,但求客观公正,勿违彼时言!
  14. 软考计算机英语词汇,软考计算机专业英语常用词汇(字母D-E)
  15. QT项目之键盘控制光标移动
  16. 做PPT不要傻乎乎直接插入图片,一键处理,秒变高逼格
  17. android root 蓝牙,真正免root的蓝牙一键发送详细使用教程
  18. 七牛云配置二级域名,从而避免七牛云30天自动更改域名的问题
  19. Dijkstra 算法-《数据结构》严蔚敏
  20. 美图AI绘画机器人上线,小姐姐们,新一轮头像可以换起了

热门文章

  1. WPF 基础控件之 ToggleButton 样式
  2. Synopsys Sentaurus TCAD系列教程之-- Sdevice《6》Math模块
  3. Exception和Error
  4. python except
  5. 8g内存学习计算机专业够吗,电脑内存4G和8G差距能有多大?电脑装机内存多大合适?...
  6. 《Effective C++ 3th》——实现
  7. 【PTA|Python】浙大版《Python 程序设计》题目集:第四章(适合Pythno新手的基础练习题集)
  8. Linux大师(古鲁,Guru)推荐什么?
  9. Octave的一些基本操作和语法,快速上手Octave,用实例解释
  10. mat a和matamp; a的区别