35

近实时搜索NRT(四)-html

 4 years ago
source link: https://www.amazingkoala.com.cn/Lucene/Index/2019/0925/96.html?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

近实时搜索NRT(四)

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

  • 方法一:DirectoryReader.open(final Directory directory)
  • 方法二:DirectoryReader.open(final IndexCommit indexCommit)
  • 方法三:DirectoryReader.open(final IndexWriter indexWriter)
  • 方法四:DirectoryReader.open(final IndexWriter indexWriter, boolean applyAllDeletes, boolean writeAllDeletes)

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

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

  • 方法一:DirectoryReader.openIfChanged(DirectoryReader oldReader)
  • 方法二:DirectoryReader.openIfChanged(DirectoryReader oldReader, IndexCommit commit)
  • 方法三:DirectoryReader openIfChanged(DirectoryReader oldReader, IndexWriter writer)
  • 方法四:DirectoryReader openIfChanged(DirectoryReader oldReader, IndexWriter writer, boolean applyAllDeletes)

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

openIfChange方法的流程图

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

1.png

点击查看大图

2.png

点击查看大图

从IndexCommit中获取StandardDirectoryReader

3.png

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

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

  段的段名(segName)是什么

4.png
5.png

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

  • 我们在近实时搜索NRT(一)的文章中已经介绍了一个段的完整信息用SegmentCommitInfo来描述,它包含了两部分的信息,用黄色框标注,其中第一部分的信息和第二部分在flush阶段生成(见文档提交之flush(三)生成FlushedSegment的流程点),如下图所示:
6.png

  当我们每次调用更改索引信息的方法后,例如删除操作、更新操作、软删除操作(这些操作内容见文档的增删改(上)),索引目录中每一个段可能需要被作用(apply)这些删除信息(如何作用删除信息见文档提交之flush(二)),也就是说在每一个段中,如果段的文档如果满足删除条件,那我们需要处理这些文档,而这个过程就会导致段的信息发生变化。

  在图6中,一个段的完整信息由两部分构成,我们先看第一部分,即索引文件.si包含的信息,这些信息在索引文件之si的文章中已经介绍,根据每个字段的具体含义可以看出他们都是固定的信息,我们称之为不可变部分。

  同样地第二部分中每一个字段的含义在索引文件之segments_N的文章中已经介绍,并且可以看出他们不是固定的信息,当段中的文档需要被删除时,DelGen、DeletionCount字段会发生变化,当执行更新DocValues操作时,FieldInfosGen、DocValuesGen会发生变化,我们称之为可变部分。

  oldReader对应的段信息跟IndexCommit对应的段信息下面的关系

  • 关系一:oldReader中拥有IndexCommit相同段名的段,并且这些段的信息完全相同
  • 关系二:oldReader中拥有IndexCommit相同段名的段,并且段的信息不相同
  • 关系三:oldReader中拥有某些段,而IndexCommit不拥有这些段
  • 关系四:IndexCommit中拥有某些段,而oldReader不拥有这些段

  故方法二的功能描述的是根据上述关系,获得参数IndexCommit中每一个段对应的SegmentReader(SegmentReader的概念见近实时搜索NRT(一)),最后生成一个StandardDirectoryReader,具体操作如下:

7.png

  图7所示的流程图是图3、图1中找出变更的LeafReader返回新的StandardDirectoryReader两个流程点的具体展开,它总体描述了这么一个过程:生成一个StandardDirectoryReader来读取IndexCommit对应的段的信息,如果可以使用oldReader中的一个或多个SegmentReader来读取IndexCommit对应的某一个段的信息,那我们就复用这些SegmentReader,否则就生成新的SegmentReader,最后将所有的SegmentReader添加到LeafReader数组中,生成一个StandardDirectoryReader(SegmentReader、LeafReader数组、StandardDirectoryReader三者之间的关系见近实时搜索NRT(一)文章中的图9),下面我们详细的介绍下图7的流程。

处理oldReader中不拥有的段

8.png

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

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

  • 在源码中,使用了一个Map来实现段名跟SegmentReader的映射,故根据段名就能判断oldReader中是否拥有某个段

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

处理oldReader中拥有的段

9.png

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

  • 条件一:两个段是否使用相同的索引文件格式

  • 条件二:两个段的可变部分是否是相同的

    • 可变部分是否相同通过比较图6中的DelGen、FieldInfosGen两个字段来判断,上文已经介绍不赘述

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

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

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

  • 在我们调用openIfChange()方法后,如果获得了一个新的StandardDirectoryReader,Lucene要求用户负责关闭oldReader,由于oldReader中的某些SegmentReader可能被新的或者其他StandardDirectoryReader复用(对象引用),所以不能直接关闭这些SegmentReader,通过计数的方式,当SegmentReader对应的计数为0时,就可以真正的关闭了。

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

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

点击下载附件


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK