构造对象八
本文承接 构造 IndexWriter 对象(七),继续介绍调用 IndexWriter 的构造函数的流程。
调用 IndexWriter 的构造函数的流程图
图 1:
生成对象 IndexFileDeleter
我们紧接上一篇文章,继续介绍剩余的流程点,下面先给出 IndexFileDeleter 的构造函数流程图:
IndexFileDeleter 的构造函数流程图
图 2:
执行检查点(checkPoint)工作
图 3:
在介绍当前流程点之前,我们先通过下面的流程图来介绍 执行检查点的工作
这个流程点做了哪些事情。
另外 执行检查点(checkPoint)工作
在源码中对应的方法方法定义:
public void checkpoint(SegmentInfos segmentInfos, boolean isCommit) throws IOException {
... ...
}
执行检查点(checkPoint)工作的流程图
图 4:
准备数据
图 5:
图 4 流程图的准备数据就是 checkPoint 方法的两个参数 SegmentInfos 以及 boolean。
增加 SegmentInfos 对应的索引文件的计数引用
图 6:
在后面的流程中,可能会执行索引文件的删除,如果某些索引文件被 SegmentInfos 引用,那么这些索引文件不应该被删除,防止被删除的方法就是增加 SegmentInfos 对应的索引文件的计数引用。
当 isCommit 为 true 时的处理流程
图 7:
在执行 commit()操作时,也会执行 checkPoint 的操作,那么此时的 isCommit 是位 true 的,在文章 文档提交之 commit(二) 中介绍了这个流程,不赘述。
当 isCommit 为 false 时的处理流程
图 8:
lastFiles 是一个 IndexFileDeleter 类的成员变量,它用来存放上次执行 checkPoint 的 SegmentInfos 中对应的索引文件定义如下:
private final List lastFiles = new ArrayList<>(); 所以当 isCommit 为 false 时,先尝试删除 lastFiles 中的索引文件,删除的方式就是减少每一个索引文件的计数引用,如果计数值为 0,那么该索引文件就要被删除,否则不删除,最后清空 lastFiles 中的索引文件后,将这次 SegmentInfos 对应的索引文件添加到 lastFiles 中。
结合图 6 跟图 8 我们可以发现这种流程的逻辑设计可以使得,即使对同一个 SegmentInfos 对象执行 多次 checkPoint 的操作时,如果该对象中的段没有发生变化,那么段对应索引文件的计数是不会变的(先增加计数,再减少计数),同样地,如果 SegmentInfos 中如果增加了段,能通过图 6 的流程点对该段中的索引文件执行正确的 +1 计数,如果删除了某个段,能通过图 8 的流程点 尝试删除lastFiles中的索引文件
对该段中的索引文件执行正确的-1 计数。
为什么要通过 checkPoint 来实现索引文件的删除:
Lucene 通过 IndexWriter 对象中的成员变量 SegmentInfos 来描述当前 IndexWriter 对应的索引信息,索引信息的变化通过 SegmentInfos 对象来反应,但是 SegmentInfos 对象并不真正的拥有索引文件的数据,它拥有只是这些索引文件的文件名,所以当 SegmentInfos 对应的信息发生变化时,例如某个段中包含的所有文档满足某个删除操作,该段的信息会从 SegmentInfos 中移除(段的信息即 SegmentCommitInfo,见文章 构造 IndexWriter 对象(四) 关于流程点 获得回滚(rollback)信息
的介绍),那么这个段对应的索引文件也应该要删除(如果索引文件的计数引用为 0),当然如果其他段同时引用这些索引文件,那么就不会被删除(索引文件的计数引用不为 0),也就是为什么图 7 的流程点 尝试删除lastFiles中的索引文件
为什么要带有 尝试
两个字。
我们回到当前流程点,介绍下为什么获得 StandardDirectoryReader 后需要执行 执行检查点(checkPoint)工作
:
根据图 2 的流程,我们是在构造 IndexFileDeleter 对象的流程中第一次调用 checkPoint()方法,那么 lastFiles 中必定不包含任何的数据,并且在源码中调用 checkPoint()方法的参数如下所示:
checkpoint(segmentInfos, false); segmentInfos 即 StandardDirectoryReader 中对应的索引信息(见文章 构造 IndexWriter 对象(四) 中 用StandardDirectoryReader初始化一个新的SegmentInfos对象
流程点的介绍),同时 isCommit 的值为 false,也就说在当前流程点调用 checkPoint()方法的目的就是 仅仅 为了增加 segmentInfos 对应的索引文件的计数,那么就转变为如下的问题:
为什么获得 StandardDirectoryReader 后,需要增加 segmentInfos 对应的索引文件的计数:
首先给出源码中的解释:
// Incoming SegmentInfos may have NRT changes not yet visible in the latest commit, so we have to protect its files from deletion too: 我们用一个例子来介绍上文的注释所描述的场景,完整代码见: https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/index/CheckPointInIndexFileDeleter.java 。
图 9:
图 9 中当第 62 行的 oldIndexWriter.commit()操作执行结束后,索引目录中的索引文件如下所示:
图 10:
接着执行完第 64 行的代码后,我们获得了一个 NRT 的 Reader(见文章 近实时搜索 NRT(三) 的介绍),接着第 70 行代码结束后,oldIndexWriter 新增了一篇文档 2,注意的是并没有执行 commit()操作(即没有生成新的 segments_N 文件),随后通过第 72 行的 openIfChange() 方法获得一个包含最新索引信息的 reader(即 StandardDirectoryReader),通过该 reader 获得一个 IndexCommit,IndexCommit 中包含了第 70 行代码增加的索引信息,即图 11 中以_1 为前缀的索引文件,并且在第 76 行通过 IndexWriterConfig.setIndexommit()方法将 IndexCommit 成为 newIndexWriter 的配置,在执行完第 78 行代码后,索引目录中的索引文件如下所示:
�
- 原文作者:知识铺
- 原文链接:https://geek.zshipu.com/post/%E4%BA%92%E8%81%94%E7%BD%91/%E6%9E%84%E9%80%A0%E5%AF%B9%E8%B1%A1%E5%85%AB/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com