文档索引
本文档描述了如何将文档添加到索引中。
组件
Document
- 包含实际的文档及其字段。RSAddDocumentCtx
- 用于在文档被索引时使用的每个文档的状态。索引完成后,该状态将被丢弃。ForwardIndex
- 包含文档中找到的术语。正向索引用于写入InvertedIndex
。InvertedIndex
- 一种将术语映射到适用文档中出现的索引。
架构
索引过程首先通过创建一个新的RSAddDocumentCtx
并向其添加文档开始。在内部,这被分为几个步骤。
-
提交
创建了一个
DocumentContext
,并将其与从输入接收到的文档关联起来。提交过程还将执行一些初步的缓存。 -
预处理
文档提交后,会进行预处理。预处理会对所有文档输入字段执行无状态处理。对于文本字段,这意味着对文档进行分词并创建前向索引。预处理器会将此信息存储在
AddDocumentCtx
中的每个字段变量中。然后,在索引阶段,这个计算结果会被写入持久化索引。如果文档足够大,预处理会在一个单独的线程中进行,这允许并发预处理,并且避免阻塞其他线程。如果文档较小,预处理会在主线程中进行,避免额外的上下文切换开销。
SELF_EXC_THRESHOLD
宏包含了“足够大”的阈值。文档经过预处理后,提交以进行索引。
-
索引
索引过程主要包括提交预处理阶段预先计算的结果。这一过程在单线程中完成,并以队列的形式进行。
因为文档必须按照其文档ID分配的确切顺序写入索引,而且索引过程还必须让位于其他潜在的索引过程,您可能会遇到文档ID无序写入索引的情况。为了解决这个问题,文档实际写入的顺序必须明确定义。如果只有一个线程在写入文档,那么该线程在写入时不需要担心ID的无序问题。
拥有一个单独的后台线程也有助于在多个方面进行优化,这将在后面看到。基本思想是,当有很多文档排队等待索引线程时,索引线程可以将它们视为批处理命令,从而大大减少GIL的锁定/解锁次数以及术语键需要打开和关闭的次数。
-
跳过已经索引的文档
以下阶段可能会同时操作多个文档。当一个文档被完全索引后,它会被标记为完成。当线程遍历队列时,它只会对尚未标记为完成的项目执行处理/索引操作。
-
术语合并
术语合并,或前向索引合并,是在队列中有多个文档时进行的。队列中每个文档的前向索引被扫描,并在其位置构建一个更大的主前向索引。前向索引中的每个条目都包含对原始文档的引用以及正常的偏移/分数/频率信息。
创建主前向索引可以避免每个文档多次打开常用术语键。
如果队列中只有一个文档,则不会创建主前向索引。
请注意,主前向索引的内部类型实际上不是
ForwardIndex
。 -
文档ID分配
此时,GIL 被锁定,队列中的每个文档都被分配了一个文档 ID。分配操作在写入索引之前立即完成,以减少 GIL 被锁定的次数;因此,GIL 仅在写入索引之前被锁定一次。
-
写入索引
由于GIL被锁定,任何待处理的索引数据都会被写入索引。 这通常涉及打开一个或多个Redis键,并将计算的数据写入/复制到这些键中。
完成后,将发送给定文档的回复,并释放
AddDocumentCtx
。