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