这是我的文本处理系列的第二部分。在这篇博客中,我们将研究如何将文本文档存储在可以通过查询轻松检索的表单中。我将使用流行的开源Apache Lucene索引进行说明。
系统中有两个主要的处理流程...
下图说明了这是如何在Lucene中完成的。
文档和查询都以一句话表示。在Apache Lucene中,“文档”是存储和检索的基本单位。“文档”包含多个“字段”(也称为区域)。每个“字段”包含多个“术语”(相当于单词)。为了控制文档在其包含字段中的索引方式,可以用多种方式声明一个字段,以指定是否应该分析它(索引期间的预处理步骤),索引(参与索引)还是存储(如果是它需要在查询结果中返回)。
倒排索引是存储的核心数据结构。它从术语到文档列表(其中包含该术语)以相反的方式组织。该列表(称为发布列表)按全局排序(通常由文档ID)排序。为了更快地检索,列表不仅仅是一个列表,而是一个跳过列表的层次结构。为了简单起见,我们在随后的讨论中忽略跳过列表。基于Lucene的实现,这个数据结构如下图所示。它以段文件的形式存储在磁盘上,在处理过程中它将被带入内存。
上图仅显示倒排索引。整个指数包含一个额外的正向指数如下。
原始格式的文档是从数据适配器中提取的。(这可以使Web API检索某些文本输出,抓取网页或接收HTTP文档上载)。这可以以批处理或在线方式完成。当索引处理开始时,它解析每个原始文档并分析其文本内容。典型的步骤包括...
此时,文档由多个术语组成。doc = [term1,term2 ...]。可选地,术语可以进一步组合为n-gram。之后,我们计算这个文档的词频。例如,在双向扩展中,文档将变为... doc1 - > {term1:5,term2:8,term3:4,term1_2:3,term2_3:1}我们也可以计算一个“静态分数”基于文档质量的某种度量。之后,我们将文档插入发布列表(如果存在,否则创建一个新的发布列表)为每个条款(所有n元),这将创建倒序列表结构,如上图所示。有一个推动因素可以设置为文档或字段。促进因素有效地增加了有效影响文件或领域重要性的词频。可以通过以下方式之一将文档添加到索引中; 插入,修改和删除。通常情况下,文档将首先添加到内存缓冲区,内存缓冲区组织为RAM中的倒排索引。
随着越来越多的文档被插入到内存缓冲区中,它将变满并且将被刷新到磁盘上的段文件。在后台,当M段文件被累积时,Lucene将它们合并成更大的段文件。请注意,每个级别的段文件大小呈指数增长(M,M ^ 2,M ^ 3)。这将每个查询需要搜索的段文件的数量保持在O(logN)复杂度,其中N是索引中文档的数量。Lucene还提供了一个明确的“优化”调用,将所有的段文件合并为一个。
这里我们来详细介绍合并过程,因为发布列表已经按条款垂直排序,并且由doc ID水平排序,合并两个段文件S1,S2基本上如下
考虑一个文档是一个向量(每个词作为分离的维度,相应的值是tf-idf值),查询也是一个向量。文档检索问题可以定义为查找与查询匹配的top-k最相似的文档,其中相似性定义为文档向量与查询向量之间的点积或余弦距离。tf-idf是一个归一化频率。TF(术语频率)表示术语在文档中出现多少次(通常是应用平方根或对数等压缩函数)。IDF是文档频率的倒数,如果该词出现在许多其他文档中,则用它来折扣重要性。TF-IDF有许多变种,但通常它反映了文档(或查询)与每个词的关联强度。给定包含术语[t1,t2]的查询Q,这里是我们如何获取相应的文档。一种常用的方法是“我们一次性的文件方法”,我们在这里同时遍历t1,t2的发布列表(而不是我们在开始发布列表之前遍历整个发布列表t1的“一次一词”方法的t2)。遍历过程如下所述...
这里将整个发布列表遍历。如果发布列表很长,响应时间延迟将会很长。有没有办法让我们不必遍历整个列表,仍然能够找到大概的顶级K文件?我们可以考虑一些策略。
由于我们有多个倒排索引(在内存缓冲区以及不同级别的段文件中),我们需要结合它们的结果。如果termX出现在segmentA和segmentB中,则会选取更新的版本。新鲜版本的确定如下:具有较低等级(较小尺寸)的部分将被视为更新鲜。如果两个分段文件处于同一级别,则数字较高的那个文件更新。另一方面,IDF值将是段文件中每个发布列表的相应IDF的总和(如果同一文档已更新,则该值稍微偏离,但这种差异可忽略不计)。但是,合并多个段文件的处理会导致文档检索中的处理开销。Lucene提供了一个明确的“优化”
对于大型语料库(如Web文档),索引通常分布在多台机器上。有两种分配模式:术语分区和文档分区。
在文档分区中,文档随机分布在构建索引的不同分区中。在术语分区中,术语分布在不同的分区上。我们将讨论文档分区,因为它更常用。分布式索引是由Lucene构建的其他技术提供的,例如ElasticSearch。典型设置如下...在此设置中,机器按列和行组织。每列表示文档的分区,而每行表示整个语料库的副本。
在文档索引期间,首先随机选择一排机器并分配用于构建索引。当一个新文档被抓取时,随机挑选一个来自所选行的列机器来承载文档。该文档将被发送到构建索引的这台机器。更新后的索引稍后将传播到其他行副本。在文件检索过程中,首先选择一排副本机器。然后客户端查询将被广播到选定行的每一列机器。每台机器将在其本地索引中执行搜索,并将TopM元素返回给查询处理器,该查询处理器将在返回给客户端之前合并结果。请注意,K / P <M <K,其中K是客户期望的TopK文档,P是机器的列数。注意M是一个需要调整的参数。这个分布式索引的一个注意事项是,由于发布列表横跨分区横向分割,所以我们丢失了IDF值的全局视图,否则机器无法计算TF-IDF分数。有两种方法可以减轻...