Lucene7.5.0中提供了以下四种open方法来获得StandardDirectoryReader的对象,这四种方法:
这四种open方法的详细介绍见近实时搜索NRT(一)、近实时搜索NRT(二)。
基于性能考虑,Lucene7.5.0中同时提供了以下四种openIfChange方法,这四种方法:
我们接着近实时搜索NRT(三)的内容,继续介绍openIfChange方法的流程图。
其中openIfChange的方法一&&方法二、方法三&&方法四的逻辑需要用两个流程图图1、图2展现:
图1:
点击查看大图
图2:
点击查看大图
图3:
如果oldReader是通过open方法中的方法三或者方法四获得,那么oldReader就持有IndexWriter对象(见近实时搜索NRT(三)),当调用了openIfChange的方法二,该方法就会执行图3中的流程。
在介绍图3的的流程之前,我们先介绍一下几个预备知识。
段的段名(segName)是什么
图4:
图5:
段的信息为什么会发生变化,段中的哪些信息会发生变化:
生成FlushedSegment
的流程点),如下图所示:图6:
当我们每次调用更改索引信息的方法后,例如删除操作、更新操作、软删除操作(这些操作内容见文档的增删改(上)),索引目录中每一个段可能需要被作用(apply)这些删除信息(如何作用删除信息见文档提交之flush(二)),也就是说在每一个段中,如果段的文档如果满足删除条件,那我们需要处理这些文档,而这个过程就会导致段的信息发生变化。
在图6中,一个段的完整信息由两部分构成,我们先看第一部分,即索引文件.si包含的信息,这些信息在索引文件之si的文章中已经介绍,根据每个字段的具体含义可以看出他们都是固定的信息,我们称之为不可变部分。
同样地第二部分中每一个字段的含义在索引文件之segments_N的文章中已经介绍,并且可以看出他们不是固定的信息,当段中的文档需要被删除时,DelGen、DeletionCount字段会发生变化,当执行更新DocValues操作时,FieldInfosGen、DocValuesGen会发生变化,我们称之为可变部分。
oldReader对应的段信息跟IndexCommit对应的段信息下面的关系:
故方法二的功能描述的是根据上述关系,获得参数IndexCommit中每一个段对应的SegmentReader(SegmentReader的概念见近实时搜索NRT(一)),最后生成一个StandardDirectoryReader,具体操作如下:
图7:
图7所示的流程图是图3、图1中找出变更的LeafReader
,返回新的StandardDirectoryReader
两个流程点的具体展开,它总体描述了这么一个过程:生成一个StandardDirectoryReader来读取IndexCommit对应的段的信息,如果可以使用oldReader中的一个或多个SegmentReader来读取IndexCommit对应的某一个段的信息,那我们就复用这些SegmentReader,否则就生成新的SegmentReader,最后将所有的SegmentReader添加到LeafReader数组中,生成一个StandardDirectoryReader(SegmentReader、LeafReader数组、StandardDirectoryReader三者之间的关系见近实时搜索NRT(一)文章中的图9),下面我们详细的介绍下图7的流程。
图8:
图8中,我们根据方法二的参数IndexCommit取出一个SegmentCommitInfo,首先判断oldReader中是否拥有该段,判断方式即根据oldReader中是否拥有相同段名的段,如果没有找到,即满足上文中的关系四,那么我们根据该SegmentCommitInfo生成一个新的SegmentReader,添加到LeafReader数组中。
如何判断oldReader中是否拥有相同段名的段:
当处理完IndexCommit中所有的SegmentCommitInfo以后,我们根据LeafReader数组中的SegmentReader生成一个新的StandardDirectoryReader。
图9:
当oldReader中拥有IndexCommit中相同段名的段,那么我们通过以下两个条件来判断两个段是否一样,即判断属于上文中的关系一还是关系二:
条件一:两个段是否使用相同的索引文件格式
条件二:两个段的可变部分是否是相同的
不同时满足上面两个条件的话,即上文中的关系二,那么执行生成一个新的SegmentReader
跟SegmentReader添加到LeafReader数组中
的流程,上文已经介绍。
如果同时满足上面的两个条件,那么就可以复用oldReader中的SegmentReader
,然后增加这个SegmentReader对应的计数值,计数值描述了引用该SegmentReader的其他Reader的个数。
为什么要增加这个SegmentReader的计数:
对于上文中的关系三,说明oldReader中的那些段是在生成IndexCommit之后生成的。
基于篇幅,剩余的流程点将在下一篇文章中展开。
点击下载附件