段的多线程查询(二)(Lucene 10.0.0)
Lu Xugang Lv6

众所周知Lucene的索引数据由一个或多个段组成,并且通过下列方式定义一个IndexSearcher后就可以实现段的多线程查询:

1
2
3
4
public IndexSearcher(IndexReaderContext context, Executor executor)
{
... ...
}

在Lucene 10.0.0之前,Lucene首先依据划分规则将段分配到不同的slice中,每个slice由一个线程负责查询,该线程依次对其包含的段进行循环查询(参见图1中的slice)。

虽然多线程能够加速所有段的查询,但它无法解决单个大段(single big segment)带来的性能瓶颈问题(详见LUCENE-8675)。该issue中提到的一个解决方案是引入段内并发查询(intra-segment search concurrency)。

最终在Lucene 10.0.0中实现了该方案。简而言之,该方案将单个大段拆分为多个小段,每个小段作为一个独立的slice,其余段则依照原有的方式进行分配。

Slice

我们可以通过一个例子来说明优化前后的分配方式。假设我们有以下几个段及其包含的文档数量:

段的编号 文档数量
段0 170_000
段1 2000_000
段2 30_000
段3 180_000

图1:

查看大图

单个大段允许拆分为最多5个小段。

拆分文档集合

单个大段拆分为多个小段的过程实际上是一种逻辑拆分,它不会真正改变底层的物理数据结构。在 Lucene 中,描述单个段的数据结构是 LeafReaderContext。在优化后的方案中,LeafReaderContext被逻辑拆分为多个名为 LeafReaderContextPartition 的数据结构。

图2:

对于未被拆分的段,也会用LeafReaderContextPartition进行包装,保持一致性便于后续查询逻辑。

以图1中的段2为例:

图3:

换言之,尽管5个线程在查询图2中这5个 LeafReaderContextPartition 的数据时,从物理上仍在访问段1,但它们各自处理不同的文档编号区间。

适配变更

实现了段内并发查询的功能后,需要对Lucene一些现有的其他功能进行适配才能保证查询正常工作。其中一个需要适配的就是TotalHitCountCollector

TotalHitCountCollector

在文章Count(Lucene 9.11.0)中详细介绍了TotalHitCountCollector,最好先看下这篇文章,因为一些概念不会在本文中展开介绍。

TotalHitCountCollector的功能是用来统计某个Query对应命中文档的数量count。它提供了两种方式进行统计:

  • 方式一:基于Weight#count,以次线性时间复杂度(sub-linear)统计
  • 方式二:基于收集器Collector,以线性时间复杂度统计,count响应时间与文档数量成正比

我们先看下基于方式二,统计文档的数量count是如何实现的:

图4:

查看大图

对于方式二,我们不需要适配变更,被拆分后的段之间是相互独立工作的,比如在段1(partition-2)中只会统计文档号集合[400_000, 800_000]中满足查询条件的count,即count2,因此只需要在最后通过Reduce将这些段的命中数量统计相加就可以得到在段1中的count值,我们称之为countSum

然而基于方式一时,如果还是按照Lucene10.0.0之前的逻辑就会出现问题,因为在任意一个小段中通过Weight#count获取到是段1countcountSum,就会出现下面的错误:

图5:

查看大图

也就说如果采用方式一,我们只需要任意一个线程计算countSum就可以了,并且该结果可以让其他线程感知,当获知其他线程已经计算出countSum,那么自身就不再计算,直接退出即可。

图6:

查看大图

图6中,段1(partition-1)成功抢占临界区,然后通过Weight#count获取段1中满足查询条件的count

我们将图4跟图6的逻辑合并下就是适配变更后的新逻辑:

图7:

查看大图

改进

当前版本默认不启用段内并发查询,因为有些Query比如PointRangeQuery会有性能损失。其原因是这类Query在查询前会提前计算一些内容,开启段内并发查询会重复这些计算,当解决这些问题后才会开启段内并发查询,见GITHUB-13745

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