最近在复习信息检索,看到建立倒排索引的算法这块,觉得还挺有用的,记录一下叭,以后还能无聊翻一翻~
目录
一、基于块的排序索引构建算法 BSMI
1.背景:
对于大规模文档集,即使是大型计算机想要在内存中对所有词项-文档ID对进行排序,也是一件十分困难的事情。 因此基于内存不足,结合磁盘排序需要太多的磁盘寻道过程,必须使用基于磁盘的外部排序算法。
2.具体步骤:
第一步,将文档集分割成几个大小相等的块, 第二步,将每个部分的词项-ID对在内存中进行排序, 第三步,将中间产生的结果写入磁盘中, 第四步,将所有的块合并成一个大的有序的倒排索引。
3.实例:需要对T = 100,000,000条无位置信息的倒排记录进行排序,其中每条倒排记录需要12字节。
定义一个能够包含10,000,000条上述倒排记录的数据块,这个数据块很容易放入内存中(12*10M=120M)
对于文档集有10个数据块。
对每个块:倒排记录累积到10,000,000条,在内存中排序,写回磁盘。最后将所有的块合并成一个大的有序的倒排索引。
二、内存式单遍扫描索引构建算法 SPIMI
1.关键思想一:对每个块都产生一个独立的词典。逐一处理词条流中的每个词项,如果词项是第一次出现,那么将之加入词典。 不需要在块之间进行term-termID的映射。
2.关键思想二:对倒排记录表不排序,按照他们出现的先后顺序排列。
3.基于上述思想可以对每个块生成一个完整的倒排索引,这些独立的索引最后合并一个大索引。
三、分布式索引构建:MapReduce
对于Web数据级别的数据建立索引,必须使用分布式计算机集群(单台机器都是有可能出现故障的)。
1.主要思想:
- 维持一台主机(Master)来指挥索引构建任务,这台主机被认为是安全的;
- 将索引划分成多组并行任务;
- 主机将把每个任务分配给某个缓冲池中的空闲机器来执行。
2.两类并行任务分配给两类机器:
- 分析器(Parser),倒排器(Inverter)
将输入的文档集分片(split) (对应于BSBI/SPIMI算法中的块);每个数据片都是一个文档子集。
3.分析器:
- 主节点将一个数据片分配给一台空闲的分析器
- 分析器一次读一篇文档然后输出 (term, docID) 对
- 分析器将这些对又分成 j 个词项分区
- 每个分区按照词项首字母进行划分
4.倒排器:
- 倒排器收集对应某一term分区所有的(term,docID) 对(即倒排记录表)
- 排序并写进倒排记录表
四、动态索引构建:如何随着文档集变化更新索引
(一)辅助索引方式
- 在磁盘上维护一个大的主索引(Main index)
- 新文档放入内存中较小的辅助索引(Auxiliary index)中
- 同时搜索两个索引,然后合并结果
- 定期将辅助索引合并到主索引中
删除的处理:
- 采用无效位向量(Invalidation bit-vector)来表示删除的文档
- 利用该维向量过滤返回的结果,以去掉已删除文档
时间复杂度:
假定每个辅助索引的大小为 a,T是所有倒排记录的个数。
由于每次合并都需要处理每个倒排记录:a + 2a + 3a + 4a + … + na = a T(T+1)/2*
因此索引构建时间为O(T²)
(二)对数合并
- 维护一系列索引,其中每个索引是前一个索引的两倍大小
- 将最小的索引 (Z0) 置于内存
- 其他更大的索引 (I0, I1, . . . ) 置于磁盘
- 如果 Z0 变得太大 (> n), 则将它作为 I0 写到磁盘中(如果 I0 不存在)
- 或者和 I0 合并 (如果 I0 已经存在),并将合并结果作为 I1 写到磁盘中 (如果 I1 不存在),或者和 I1 合并 (如果 I0 已经存在),依此类推……
对数合并算法能够缓解 (随时间增长) 索引合并的开销,用户并不感觉到响应时间上有明显延迟。
时间复杂度:
索引构建时间为 O(TlogT) (T 是所有倒排记录的个数)
因此,对数合并的复杂度比辅助索引方式要低一个数量级。