在近实时搜索NRT(二)的文章中我们提到,Lucene提供了四种方法来获得StandardDirectoryReader对象,这里先简单总结下这四种open方法获取StandardDirectoryReader的差异:
方法一:DirectoryReader.open(final Directory directory)
方法二:DirectoryReader.open(final IndexCommit indexCommit)
不属于
NRT方法三:DirectoryReader.open(final IndexWriter indexWriter)
方法四:DirectoryReader.open(final IndexWriter indexWriter, boolean applyAllDeletes, boolean writeAllDeletes)
属于
NRT在近实时搜索NRT(一)、近实时搜索NRT(二)中我们了解到,无论调用哪一个上述介绍的方法,其相同的逻辑都是将一个段的信息segmentCommitInfo封装为一个LeafReader,最后将多个LeafReader封装为StandardDirectoryReader,当索引目录中的索引信息发生更改时,我们可以通过重新调用上述的方法来获得最新的StandardDirectoryReader,但是基于下面的几个考虑,Lucene提供了性能更高的openIfChanged方法来获得最新的StandardDirectoryReader:
Lucene7.5.0中提供了以下四种openIfChange方法,这四种方法:
其中openIfChange的方法一&&方法二、方法三&&方法四的逻辑需要用两个流程图图1、图2展现:
图1:
点击查看大图
图2:
点击查看大图
在介绍每一个流程点之前,我们先大致先说下图1、图2的流程,两个流程图总体描述了旧的StandardDirectoryReader,即oldReader(DirectoryReader的子类,见近实时搜索NRT(一))在经过一系列的流程后,判断是否需要生成新的StandardDirectoryReader,如果不需要那么返回null,否则生成一个新的StandardDirectoryReader,生成的新的StandardDirectoryReader的方法有两个,即图1、图2中用红色跟紫色标注的两个流程点,而这两种获取新的StandardDirectoryReader的方法即近实时搜索NRT(一)、近实时搜索NRT(二)介绍的四种open方法,如下图所示:
图3:
点击查看大图
下面我们先介绍图1中的每一个流程点。
图4:
IndexWriter是否为空描述的是旧的StandardDirectoryReader,即oldReader中是否持有IndexWriter对象的引用。
如何判断oldReader中是否持有IndexWriter对象的引用:
图5:
如果oldReader是通过open方法中的方法一或者方法二获得的,并且调用openIfChange的方法一,由于该方法没有indexCommit参数,故该方法会执行图5中的流程。
方法一只提供了一个oldReader的参数,并且没有持有IndexWriter对象的引用,所以判断是否需要获取新的StandardDirectoryReader的方式为根据索引目录中最后一次commit,对比最后一次commit对应的SegmentInfos对象跟oldReader中的SegmentInfos的版本号Version是否一致,如果不一致,说明索引信息在生成oldReader之后发生了变化,那么我们需要重新生成一个新的StandardDirectoryReader,否则返回null。
SegmentInfos是什么:
获得所有段的信息集合SegmentInfos
的介绍SegmentInfos的版本号Version是什么:
段的什么变化会引起版本号Version的变化:
图6:
图6中,红框标注的为某次提交对应的SegmentInfos的版本号。
如何根据最后一次commit获得SegmentInfos:
获取segment_N文件
、获得所有段的信息集合SegmentInfos
的介绍图5中如果根据Directory判断索引发生了变化,那么通过图3的流程获得一个新的StandardDirectoryReader。
如何获得新的StandardDirectoryReader:
找出变更的LeafReader
流程点,由于后面的流程也有该操作,我们留到下一篇文章介绍,这里先挖个坑图7:
如果oldReader是通过open方法中的方法一或者方法二获得的,并且调用openIfChange的方法二,由于该方法有indexCommit,那么该方法会执行图7中的流程。
方法二描述的是根据参数IndexCommit来获得对应的StandardDirectoryReader,另外通过比较oldReader中对应的segment_N文件名是否跟方法二的参数IndexCommit中的segment_N文件名是否相同来判断是否需要获得新的StandardDirectoryReader。
如何通过oldReader获得对应的segment_N文件:
lastGeneration什么时候被赋值的:
生成新的Segment_N文件
流程中我们说到,该流程会生成一个generation用来设置这次提交生成的segment_N的N值,同时generation值会赋值给lastGeneration另外IndexCommit类中有一个变量叫做segmentsFileName,该变量用来保存segment_N的文件名。
当判断出segment_N的文件名不一致,那么我们需要重新获得StandardDirectoryReader,即图7中的找出变更的LeafReader
流程点,同样的,详细的获得过程在下一篇文章中展开。
基于篇幅,剩余的流程点将在下一篇文章中展开。
点击下载附件