如何在 Manticore Search 3 中改变杀死列表

在本文中,我们将讨论杀死列表在 Manticore Search 3 中的工作原理。

普通索引在添加新文档方面是不可变的:一旦创建,就无法添加更多数据,只能更新现有文档的属性。为了使索引与主数据(可以是数据库或文件)保持一致,需要通过执行完全重建来刷新索引。此操作可能需要时间。在某些情况下,完全重建可能需要几个小时甚至更长时间。

这意味着可搜索的数据可能落后于原始数据存储,最新内容在索引重建之前有一个等待时间。为了解决这个问题,引入了增量索引的概念。增量索引的结构与更大的(即“主”)索引相同,但它用于获取在主索引构建后添加到数据库的文档。获取点通常是文档 ID 或时间点。

虽然增量索引捕获较新的文档(这些文档从未存在过),但在大多数情况下,还希望捕获已修改的文档。另一个常见的要求是能够以某种方式丢弃已删除的文档。已修改的文档可以包含在增量索引中,但它们引入了一个问题:在主索引和增量索引上搜索将带来同一文档的两个版本 - 主索引中的旧版本和增量索引中的新版本 - 而引擎不知道选择哪个。

为了解决这些问题,添加了一个新概念:杀死列表 - 在增量索引中已知为已修改或已删除的文档 ID 列表,以便在主索引中搜索时忽略它们。

到目前为止,一切都很好。然而,在 v2 中,引擎必须在与增量索引的结果集合并之前,将杀死列表应用于从主索引提取的结果集,以提供最终结果。虽然一般来说,这对许多用户来说效果很好,但在每个查询上应用杀死列表确实会影响性能。这在小索引或小杀死列表上并不明显,但在需要“花费很长时间”重建的大索引上,它开始显现出影响,增量索引可能最终会有大量的杀死列表集。

<img src="killlists-v2-optimized.webp" alt="img"> 2.x 中的杀死列表

Manticore 3 通过对索引存储引擎进行大规模升级引入了一个重大变化。杀死列表也需要进行更改。

这有两个原因:现有的杀死列表方式在某些边缘情况下被证明是有问题的,并且它也与新的存储引擎不太匹配。

因此,与其在每次查询时应用杀死列表,为什么不一次性完成呢?在 v3 中,在增量索引的源中,我们仍然定义一个杀死列表的源(sql_query_killlist),但在索引配置中,我们需要定义杀死列表的目标。

当索引被加载时,引擎会查看是否有需要应用的杀死列表。如果找到一个(或多个),它会通过将匹配的文档标记为已删除来将该杀死列表应用于索引。当在索引上执行查询时,这些标记的文档会被简单地忽略(就像它们不存在一样)。由于这种抑制在启动或索引轮换时已经完成,因此不再需要增量索引来确保已删除的文档不再出现在结果中。

<img src="killlists-v3-optimized.webp" alt="img"> 杀死列表目标在 killlist_target 索引指令中定义。该指令期望一个索引列表和应用杀死列表的模式。目前支持 3 种模式:

  • kl - 来自定义杀死列表(通过 sql_query_killlist)的文档 ID 将用于抑制

  • id - 使用索引中的文档 ID(并且任何定义的 sql_query_killlist 将被忽略)

  • 或者默认情况下,如果您不指定 'kl' 或 'id',则将同时使用索引中的文档 ID 和 sql_query_killlist

示例

index delta {
  ...
  killlist_target = index_one:kl, index_two:id
  ...
}

目标指令可以使用 ALTER TABLE 命令进行更改,但为了使其生效,目标索引必须重新加载。此外,ALTER 不能“禁用”目标索引上已经删除的 ID(通过将索引从目标列表中移除)。

新的杀死列表工作方式提高了查询性能,因为现在在查询时没有额外的操作来将找到的文档 ID 与抑制列表进行比较。更重要的是,已抑制文档 ID 的永久标记意味着在每个查询中需要搜索的 ID 列表更短。它还增加了灵活性,因为不仅可以使用来自专用列表(由 sql_killlist_query 生成)的 ID 进行抑制,还可以在需要时使用整个索引的文档 ID。

安装Manticore Search

安装Manticore Search