索引文件的读取(九)(Lucene 8.4.0)

  本文承接文章索引文件的读取(八)之tim&&tip,继续介绍剩余的流程点,先给出流程图:

获取满足TermRangeQuery查询条件的term集合的流程图

图1:

获取迭代器IntersectTermsEnum

图2:

  IntersectTermsEnum类继承于抽象类TermsEnum,TermsEnum在Lucene中到处可见,它封装了一个段中term的相关操作,下面罗列了TermsEnum类中的几个常用/常见的方法:

TermsEnum

判断段中是否存在某个term

图3:

  seekExact(BytesRef text)方法用来判断term是否在当前段中,其中参数text即term,下文中参数text统称为term

获取迭代状态

图4:

  根据某个term判断当前迭代状态,一共有三种迭代状态,如下所示:

图5:

根据ord判断段中是否存在某个term

图6:

  根据ord值判断段中是否存在某个term,ord描述了term之间的大小关系,在文章索引文件的读取(五)之dvd&&dvm中我们介绍了ord跟term的内容,这里不赘述。

获取当前term 的ord值

图7:

  根据迭代器目前迭代位置对应的term找到该term对应的ord值。

获取当前term的docFreq、totalTermFreq

图8:

  docFreq即包含当前term的文档数量,totalTermFreq为当前term在每一篇文档中出现的次数的总和。

IntersectTermsEnum

  在获取迭代器IntersectTermsEnum的过程中,即在IntersectTermsEnum的构造函数中,本篇文章中我们只关心其中的一个逻辑,那就是初始化IntersectTermsEnumFrame对象,它用来描述段中第一个term所在的NodeBlock(见文章索引文件tim&&tip)的信息,生成该对象的过程即读取索引文件tim&&tip的过程:

图9:

  在文章索引文件的读取(七)之tim&&tip中我们说到,索引文件.tim&&.tip中的RootCodeLength跟RootCodeValue字段会用于生成FiledReader对象,在构造该对象期间,会根据这两个字段计算出long类型的rootBlockFP,它就是前缀为"[ ]"的PendingBlock合并信息(见文章索引文件的生成(六)之tim&&tip),当rootBLockFP执行右移两个bit的操作后,就获得了fp,它指向了段中第一个term所属的NodeBlock在索引文件.tim中的起始读取位置,随后读取NodeBlock中的信息,这些信息用于生成IntersectTermsEnumFrame对象。

获取Term并判断是否满足查询条件

图10:

  在这个两个流程点中核心的两个步骤为获取term判断term是否满足查询条件

获取term

  在图9中,我们已经获得了第一个term所属的NodeBlock,如果想要获取下一个term,根据Suffix字段的数据结构,获取方式有所不同,我们先看下图9中Suffix字段的数据结构,它具有两种类型:

图11:

  当读取到类型一的数据结构时,意味着term的信息都在当前NodeBlock中,当读取到类型二的数据结构,意味着term信息在其他NodeBlock中,注意的是:Length字段是一个组合编码,该字段最后一个bit为0时说明Suffix为类型一,为1时候Suffix为类型二

  在文章索引文件tim&&tip中已经给出了例子,我们这里再次列出:

图12:

图13:

  图13中可以看出,前缀为"ab"的信息在另一个NodeBlock中,至于为什么会分布在另一个NodeBlock中,见文章索引文件的生成(六)之tim&&tip的介绍。

判断term是否满足查询条件

  判断的逻辑用一句话可以总结:在DFA(Deterministic Finite Automaton)中,如果term的每个字符(label)能根据转移函数从当前状态转移到下一个状态,并且要求字符的当前状态为前一个字符的下一个状态,并且最后一个字符对应的下一个状态为可接受状态,那么term满足查询条件

  上述逻辑的例子在文章Automaton中已经介绍,不赘述。

  到这里,我们应该会提出这样的疑问,既然知道了TermRangeQuery的查询范围minValue、maxValue,为什么不直接通过简单的字符比较来判断term是否满足查询条件,简单的字符比较例如FutureArrays.compareUnsigned方法,从最高位的字符开始按照字典序进行比较,这块内容将在下一篇文章中展开。

收集Term

图14:

  收集满足查询条件的term后,如果term的数量超过某个阈值,处理方式也是不同的,在源码中,通过BOOLEAN_REWRITE_TERM_COUNT_THRESHOLD定义阈值,默认值为16。

未达到阈值

  term的数量不大于16,那么TermRangeQuery转变为BooleanQuery,其中每个term生成TermQuery,作为BooleanQuery的子查询,并且TermQuery之间的关系为SHOULD

达到阈值

  基于篇幅,这块内容将在下一篇文章中展开。

结语

  

点击下载附件