索引文件的生成(十八)之dvm&&dvd(Lucene 8.4.0)
Lu Xugang Lv6

  索引文件.dvm&&.dvd中根据文档中包含的不同类型的DocValuesFields,包含下面的DocValues信息:

  本篇文章开始介绍生成索引文件.dvd、.dvm之SortedDocValues、SortedSetDocValues的内容,在此之前,我们先介绍下在索引(index)阶段以及flush阶段,Lucene是如何收集文档中的SortedDocValues、SortedSetDocValues信息。

SortedDocValues

  SortedDocValues信息对应的是在文档中SortedDocValuesField域中的信息,它同NumericDocValues一样,在一篇文档中,相同域名的SortedDocValuesField只能有一个,否则就会报错,如下所示:

图1:

图2:

  图1中,在一篇文档中有两个域名为"level"的SortedDocValuesField,那么会抛出图2中的错误,如果你期望支持多值,那么可以使用SortedSetDocValues,下文中会详细介绍。

收集文档的SortedDocValues信息

  收集SortedDocValues信息的代码入口方法为:https://github.com/LuXugang/Lucene-7.5.0/blob/master/solr-8.4.0/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesWriter.java 的 addValue(int docID, BytesRef value)方法,收集的信息有:DocId、TermId、pending、sortedValues[ ]数组、ord、ordMap[ ]数组

  我们根据一个例子来介绍上述收集的信息:

图3:

DocId

  DocId即包含SortedDocValuesField域的文档的文档号,并且使用DocsWithFieldSet存储,DocsWithFieldSet存储文档号的过程在文章索引文件的生成(十五)之dvm&&dvd已经介绍,不赘述。

TermId

  根据处理文档的顺序,有序的处理每一篇文档中的SortedDocValuesField,并且对每一个SortedDocValuesField的域值用一个从0开始递增的termId来描述,相同的域值具有相同的termId,图3的例子对应的termId如下所示:

表一:

域值 termId
a 0
d 1
b 2
c 3

pending

  pending是PackedLongValues.Builder对象,这个对象我们不需要具体了解,我们只需要知道,在这个对象有一个currentValues[ ]数组,它用来收集每篇文档中SortedDocValuesField域的域值对应的termId,图3的例子对应的currentValues[ ]如下所示:

图4:

  图4中,注意的是currentValues[ ]数组的数组下标描述的不是文档号。

sortedValues[ ]数组 && ord

  sortedValues[ ]数组的数组元素是termId(去重),数组下标为ord。下面的一句话很重要:数组元素是有序的,但是排序规则不是根据termId的值,而是根据termId对应的域值的字典序,图3的例子对应的sortedValues[ ]数组如下所示:

图5:

ordMap[ ]数组

  sortedValues[]数组中实现了 数组下标ord 到 数组元素termId的映射,而ordMap[]数组则是实现了 数组下标termId 到 数组元素 ord的映射,图3的例子对应的ordMap[ ]数组如下所示:

图6:

  以上就是索引(index)阶段以及flush阶段收集的内容,至于收集这些信息的作用,将在后续的文章中提及。

SortedSetDocValues

  SortedSetDocValues信息对应的是在文档中SortedSetDocValuesField域中的信息,它跟SortedDocValues不用的是,一篇文章中允许多个相同域名的SortedSetDocValuesField,使得在搜索阶段,能提供更灵活的排序,同样我们以一个例子来介绍所谓的更灵活的排序。

图7:

  在搜索阶段,对于某一个SortedSetDocValues,可以支持四种方式的排序:

  • MIN:选取文档中域值最小的参与排序
  • MIDDLE_MIN:如果域值的数量为偶数,选取文档中的中间值较小的域值参与排序
  • MIDDLE_MAX:如果域值的数量为偶数,选取文档中的中间值较大的域值参与排序
  • MAX:选取文档中域值最大的参与排序

  以下是源码中对上述的解释:

图8:

  如果在搜索阶段,我们定义了MIDDLE_MAX的排序规则,如下所示:

图9:

  对于上述排序规则,由于图6中每篇文档中的SortedSetDocValuesField数量为偶数,那么选取中间值较大的域值参与排序,如下所示:

文档号 参与排序的域值(MIDDLE_MAX)
0 l
1 i
2 j
3 k

  那么搜索出来的文档是有序的,如下所示:

图10:

  上述的demo见 https://github.com/LuXugang/Lucene-7.5.0/blob/master/LuceneDemo8.4.0/src/main/java/io/lucene/DcoValues/SortedSetDocValuesTest.java

收集文档的SortedSetDocValues信息

  介绍完SortedDocValues用法之后,我们继续介绍在索引(index)阶段以及flush阶段,收集SortedDocValues信息的内容,收集信息的代码入口方法为:https://github.com/LuXugang/Lucene-7.5.0/blob/master/solr-8.4.0/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesWriter.java 的 addValue(int docID, BytesRef value)方法,需要收集的信息,包括:DocId、TermId、sortedValues[ ]数组、ord、ordMap[ ]数组、pending、pendingCounts

  其中DocId、TermId、sortedValues[ ]数组、ord、ordMap[ ]数组的含义跟SortedDocValues是一致的,故只介绍pending、pendingCounts。

pending

  同样使用pending中的currentValues[ ]数组收集每篇文档中SortedSetDocValues域的域值对应的termId,注意的是一篇文档中可能包含多个域值,并且可能还是重复的域值,为了能更好的理解pending,我们需要重新写一个例子:

图11:

  图11的例子对应的termId如下所示:

域值 termId
a 0
b 1
c 2
d 3

  图11的例子对应的currentValues[ ]数组如下所示:

图12:

  对于上述的currentValues[ ]数组,需要说明两个重点:

  • 重点一:如果一篇文档中包含重复的域值,那么只需要记录一个即可,例如文档0中,有两个域值为"b"的SortedSetDocValuesField
  • 重点二:一篇文档中域值对应的termId是有序存放到currentValues[ ]数组中的,例如文档4,按照域值处理顺序为先处理域值"d",对应termId为3.再处理域值"a",对应termId为0,但最终根据termId从小到大的顺序存储到了currentValues[ ]数组中,至于这么处理的原因,暂时不介绍,在后面的文章中会介绍。

pendingCounts

  pendingCounts跟pending一样都是PackedLongValues.Builder对象,所以同样我们只需要关系pendingCounts中的currentValues[ ]数组,它存储了每篇文档中包含的termId的数量,图11的例子对应的currentValues[ ]数组如下所示:

图13:

  同样的,收集SortedSetDocValues信息的作用,将在介绍生成索引文件.dvd、.dvm之SortedDocValues、SortedSetDocValues的文章中。

结语

  无。

点击下载附件

 BUY ME A COFFEE
 Comments
Comment plugin failed to load
Loading comment plugin