近实时搜索NRT(四)

  Lucene7.5.0中提供了以下四种open方法来获得StandardDirectoryReader的对象,这四种方法:

  这四种open方法的详细介绍见近实时搜索NRT(一)近实时搜索NRT(二)

  基于性能考虑,Lucene7.5.0中同时提供了以下四种openIfChange方法,这四种方法:

  我们接着近实时搜索NRT(三)的内容,继续介绍openIfChange方法的流程图。

openIfChange方法的流程图

  其中openIfChange的方法一&&方法二、方法三&&方法四的逻辑需要用两个流程图图1、图2展现:

图1:

点击查看大图

图2:

点击查看大图

从IndexCommit中获取StandardDirectoryReader

图3:

  如果oldReader是通过open方法中的方法三或者方法四获得,那么oldReader就持有IndexWriter对象(见近实时搜索NRT(三)),当调用了openIfChange的方法二,该方法就会执行图3中的流程。

  在介绍图3的的流程之前,我们先介绍一下几个预备知识。

  段的段名(segName)是什么

图4:

图5:

  段的信息为什么会发生变化,段中的哪些信息会发生变化

图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的流程。

处理oldReader中不拥有的段

图8:

  图8中,我们根据方法二的参数IndexCommit取出一个SegmentCommitInfo,首先判断oldReader中是否拥有该段,判断方式即根据oldReader中是否拥有相同段名的段,如果没有找到,即满足上文中的关系四,那么我们根据该SegmentCommitInfo生成一个新的SegmentReader,添加到LeafReader数组中。

  如何判断oldReader中是否拥有相同段名的段

  当处理完IndexCommit中所有的SegmentCommitInfo以后,我们根据LeafReader数组中的SegmentReader生成一个新的StandardDirectoryReader。

处理oldReader中拥有的段

图9:

  当oldReader中拥有IndexCommit中相同段名的段,那么我们通过以下两个条件来判断两个段是否一样,即判断属于上文中的关系一还是关系二:

  不同时满足上面两个条件的话,即上文中的关系二,那么执行生成一个新的SegmentReaderSegmentReader添加到LeafReader数组中的流程,上文已经介绍。

  如果同时满足上面的两个条件,那么就可以复用oldReader中的SegmentReader,然后增加这个SegmentReader对应的计数值,计数值描述了引用该SegmentReader的其他Reader的个数。

  为什么要增加这个SegmentReader的计数

  对于上文中的关系三,说明oldReader中的那些段是在生成IndexCommit之后生成的。

结语

   基于篇幅,剩余的流程点将在下一篇文章中展开。

点击下载附件