构造对象五
系列文章:
本文承接 构造 IndexWriter 对象(四),继续介绍调用 IndexWriter 的构造函数的流程。
调用 IndexWriter 的构造函数的流程图
图 1:
根据不同的 OpenMode 执行对应的工作
在上一篇文章中,我们介绍了执行 APPEND 模式下的工作的部分流程点,故继续对剩余的流程进行介绍。
执行 APPEND 模式下的工作的流程图
图 2:
用索引目录中最新的提交初始化一个新 SegmentInfos 对象
图 3:
由于 StandardDirectoryReader 为空,那么就从索引目录中初始化一个新 SegmentInfos 对象(见 构造 IndexWriter 对象(三)),即通过找到索引目录中的 segments_N 文件读取索引信息。
当索引目录中有多个 segments_N 文件时该如何选择:
- Lucene 设定为读取最新的一次提交,即选取 segments_N 的 N 值最大的那个,因为 N 越大意味着更新的提交(commit()操作)
IndexCommit 是否为空?
图 4:
在 构造 IndexWriter 对象(四) 文章中我们说到,图 2 中 StandardDirectoryReader 为空的情况分为下面两种:
- 用户没有设置 IndexCommit
- 用户设置了 IndexCommit,但是 IndexCommit 中没有 StandardDirectoryReader 对象的信息
如果是第一种情况的进入到当前流程点,那么当前流程点的出口为是,那么以 APPEND 模式打开的 IndexWriter 追加的索引信息为索引目录中最新的一次提交。
配置检查 3
图 5:
如果 IndexCommit 不为空,那么 IndexCommit 必定是 CommitPoint 或者 SnapshotCommitPoint 对象,接着就需要执行下面的配置检查:
if (commit.getDirectory() != directoryOrig) {
throw new IllegalArgumentException("IndexCommit's directory doesn't match my directory, expected=" + directoryOrig + ", got=" + commit.getDirectory());
}
其中 commit 即 IndexCommit 对象、directoryOrg 为 IndexWriter 的工作目录,这个配置检查意味着要求当前构造的 IndexWriter 的工作目录必须和 IndexCommit 对应的索引信息所在的目录必须一致
用 IndexCommit 更新 SegmentInfos 对象
图 6:
通过 IndexCommit 读取对应的索引信息,然后更新到上文中已经完成初始化的 SegmentInfos 对象中。
更新 SegmentInfos 的 version
图 7:
对一个已经初始化的 SegmentInfos 进行更新操作必然需要更新 version,version 的概念在 构造 IndexWriter 对象(三) 的文章中介绍,这里不赘述。
至此,我们介绍完了分别在 CREATE、APPEND、CREATE_AND_APPEND 模式下的执行流程,接着我们根据图 1 介绍剩余的流程点。
检查 IndexSort 合法性
图 8:
如果设置了 IndexSort,那么在生成一个段的过程中,Lucene 会根据用户提供的排序规则对段内的文档进行排序,关于 IndexSort 的详细介绍见文章 构造 IndexWriter 对象(一), 如果用户通过 IndexWriterConfig.setIndexSort(Sort sort) 设置了 IndexSort 配置,那么需要对参数 Sort 进行合法性检查,检查逻辑如下所示:
检查 IndexSort 合法性的流程图
图 9:
SegmentInfos 对象
图 10:
为什么检查 IndexSort 合法性的准备数据是 SegmentInfos 对象:
SegmentInfos 对象是索引文件 segments_N 跟。si 文件在内存中的描述,如下图所示:
图 11:
由图 11 可以看出,我们只能通过 SegmentInfos 找到每一个段(图 11 中的 SegmentCommitInfo)的段内排序规则 IndexSort(图 11 总红色标注)。
是否还有未处理的 SegmentCommitInfo?
图 12:
对每一个 SegmentCommitInfo(见图 11)进行 IndexSort 合法性检查,只要有一个段判断为非法,那么就抛出异常,即构造 IndexWriter 对象失败。
比较 Lucene 版本
图 13:
如果通过图 11 的[索引文件。si](https://www.amazingkoala.com.cn/Lucene/suoyinwenjian/2019/0605/63.html)中的 IndexSort 字段来判断出段中没有排序规则,那么需要判断生成该段的 Lucene 版本号,代码如下:
if (segmentIndexSort == null && info.info.getVersion().onOrAfter(Version.LUCENE_6_5_0)){
throw new CorruptIndexException(“segment not sorted with indexSort=” + segmentIndexSort, info.info.toString());
} 上述代码中,segmentIndexSort 为段中的排序规则,info.info.getVersion( )中,第一个 info 是 SegmentCommitInfo,第二个 info 为 segmentInfo 对象(即索引文件。si 在内存中的描述),getVersion( )获得值即图 11 中 SegVersion。
图 13 的流程描述的是,如果正在构造的 IndexWriter 对象设置了 IndexSort 配置,并且旧索引(旧索引指的是图 1 中执行三种打开模式流程获得的索引)中一个或多个段中没有排序规则,并且生成这些段的版本号大于等于 6.5.0,那么就不能通过调用 IndexWriter 构造函数来读取旧的索引。
如何读取没有排序规则的段,并且生成这些段的 Lucene 版本号大于等于 6.5.0 的旧索引:
- 如果旧索引的版本号是 Lucene7 以上,那么通过 IndexWriter.addIndexes(Directory… dirs) 方法读取旧索引,该方法必须要求旧索引跟当前读取索引的 Lucene 主版本(即图 11 中索引文件 segments_N 的 IndexCreatedVersionMajor 字段的值)是一致的。下面的这个 demo 演示了如何添加上述旧索引: https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo/src/main/java/lucene/index/ValidateIndexSort.java 。
- 如果旧索引的版本号是 Lucene7 以下并且是 Lucene6 以上,可以通过 DirectoryReader.open(Directory directory)的方式读取
- 如果旧索引的版本号是 Lucene6 以下,那么无法读取
比较
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek/post/%E4%BA%92%E8%81%94%E7%BD%91/%E6%9E%84%E9%80%A0%E5%AF%B9%E8%B1%A1%E4%BA%94/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com