目录
信息检索导论-读书笔记(1)-信息检索导论基础知识
本文是对国科大2018-2019年春季教授的信息检索课程的复习总结,主要参考《信息检索导论》一书以及老师上课所用课件。根据书中章节的划分,本系列文章为五个部分,本文是第一部分:信息检索的基础知识,其余部分如下:
- 信息检索导论-读书笔记(1)-信息检索导论基础知识
- 信息检索导论-读书笔记(2)-相关反馈和查询扩展、概率模型待完成
- 信息检索导论-读书笔记(3)-信息检索中的机器学习和数值方法待完成
- 信息检索导论-读书笔记(4)-信息检索中的文档聚类待完成
- 信息检索导论-读书笔记(5)-信息检索的应用-Web搜索待完成
0. 本文概述
本文主要介绍信息检索的基础知识,也是搜索引擎的核心理论。首先介绍倒排索引,包括其构建之前的预处理、构建的过程、以及用于布尔查询时如何使用,然后基于上面的过程,针对具体的场景,提出了具体的改进方法:
- 如何处理短语查询?
- 进行布尔查询时存在查询拼写错误或者不能精确匹配的情况时如何处理?
- 如何为大规模文档集构建索引?
- 如何对词典和倒排记录表进行压缩以节省空间?
在对布尔查询及其扩展有了基本的了解之后,我们知道了如何从文档集中检索出匹配的文档,但是并不知道每一篇文档匹配的程度,因此剩下的内容将会介绍如何对文档和查询的匹配程度进行度量,主要包括词项权重的计算以及评分算法。
有了上面的内容,我们已经对一个简单的搜索引擎的基础组成部分有了大致的了解,最后,将会介绍如何对一个检索系统进行评价。
1. 倒排索引和布尔检索
布尔检索也称为布尔逻辑检索,是指利用布尔逻辑运算连接各个检索式,然后由检索系统执行相应逻辑计算,以找出所需信息的犯法。在该模型下,每篇文档只被看成是一些列词的集合。
为了执行布尔检索式,我们需要提前对文档集建立索引,即词项-文档关联矩阵,词项是索引的单位,我们会在下面的预处理中再次提到它,关联矩阵就是为了记录某一篇文档是否包含词表中的每个词,这里的词表指的是文档集包含的所有词项的集合,所以关联矩阵的大小是 m ∗ n m*n m∗n, m m m是文档集中的文档数量, n n n是文档集包含的所有词项的总数,矩阵中每一个值的取值范围是0或1,分别表示不包含该词项和包含该词项。
有了词项关联矩阵我们就可以对布尔检索式进行逻辑运算了,比如我们希望查找 ( A A n d B ) (A And B) (AAndB)即同时包含A和B的文档,可以取出关联矩阵中词项A的那一列和词项B的那一列,然后统计两列数据中同时取1的那些行,即是我们想要的结果。
但是词项文档矩阵有一个很严重的问题就是当文档集比较大的时候,实际上不需要很大的时候,矩阵占用的内存会急剧增长,因为这个矩阵是及其稀疏的,所以我们有了信息检索中的第一个核心概念——倒排索引。
倒排索引由词典和倒排记录表组成,词典即上面提到的词项集合,每一个词项对应一个倒排记录表,该表中的每个元素记录的是该词项在某文档中出现的一次信息,如下图:
![](https://github.com/serryuer/blog-img/raw/master/imgs/信息检索导论1/Snipaste_2019-05-03_01-28-23.png)
1.1 倒排索引的构建
倒排索引的构建过程如下所示:
- 收集需要建立索引的文档;
- 将每篇文档转化成一个个词条(token)的列表,这个过程称为词条化(tokenization);
- 进行语言学处理,产生归一化的词条来作为词项;
- 对所有文档按照其中出现的词项来建立倒排索引。
产生归一化词项的过程我们可以看做是对建立倒排索引的预处理过程,会在下面进行介绍,这里主要讲第四步,在上面的前3步处理结束后,对每篇文档建立索引时的输入就是一个归一化的词条表,也可以看成二元组 ( t e r m , d o c u m e n t I D ) (term, documentID) (term,documentID)的一个列表,建立索引的核心步骤就是将这个由所有文档的词条表组成的列表按照词项的字母顺序进行排序,同一词项在同一文档中的多次出现会合并在一起,最后整个结果分成词典和倒排记录表两部分,如下图所示:
![](https://github.com/serryuer/blog-img/raw/master/imgs/信息检索导论1/Snipaste_2019-05-03_01-38-18.png)
在最终得到的倒排记录表中,往往会将词典放在内存中,而倒排记录表放在磁盘上。
1.2. 布尔查询的处理
布尔查询包括两种操作AND 和 OR,基于倒排索引的布尔查询就是取出词项对应的倒排记录表进行合并或者交集操作,这里不做赘述。
查询优化指的是如何通过组织查询的处理过程来使处理工作量最小,对布尔查询进行优化要考虑的一个主要因素是倒排记录表的访问顺序,一个启发式的想法是按照词项的文档频率(也就是倒排记录表的长度)从小到大依次处理,如果是复合的布尔检索式,我们可以保守的估计出每一个子检索式的结果大小然后按照从小到大的顺序依次处理。
1.3 基本布尔操作的扩展以及有序检索
与布尔检索模型相对的是有序检索模型或者叫排序检索模型,后者不是通过具有精确语义的逻辑表达式来构建查询,而是采用一个或者多个词来构成自由文本查询,需要确定哪些文档最能满足用户的需求。
实际上,严格的布尔检索模型并不能满足用户的要求,实际应用中往往会在系统中加入更多的操作,比如词项近邻等。
2 词项词典及倒排记录表
上面我们讲了如何构建倒排记录表,以及在布尔查询中基础使用,接下来讲一下倒排记录表的具体实现问题,包括如何得到词项词典,以及一些扩展的索引结构。
2.1 词项集合的确定
词项集合的确定包括词条化、去除停用词、词项归一化、词干还原和词性归并。词条化是将给定的字符序列拆分成一系列子序列的过程,其中每一个子序列称为一个词条;去除停用词的目的是为了去除那些语义内容1余文档主题关系不大的高频词,同时节省存储空间;词项归一化是将看起来不完全一直的词条归纳成一个等价类,以便在他们之间进行匹配;词干还原和词性归并的目的是为了减少词的曲折变化形式,并且有时候会将派生词转化为基本形式。
2.2 基于跳表的倒排记录表快速合并算法
考虑两个大小分别为m和n的倒排记录表的合并问题,其时间复杂度是 O ( m + n ) O(m+n) O(m+n),为了优化类似查询,一种方法是采用跳表,用少量的空间去换取时间上的优化。
跳表是在构建索引的同时在倒排记录表上建立跳表,跳表指针能够提供捷径来跳过那些不可能出现在检索结果中的记录项,如下图所示:
![](https://github.com/serryuer/blog-img/raw/master/imgs/信息检索导论1/Snipaste_2019-05-03_02-50-38.png)
跳表的使用方式很直观,不再赘述。现在要考虑的问题是如何选择跳跃步长,一个简单的启发式策略是在每个 p \sqrt{p} p处放置跳表指针。
2.3 含位置信息的倒排记录表和短语查询
有时候我们需要对一个完整的短语进行检索,不希望我们的检索系统将其拆分成多个词项,这种情况下,原来的倒排索引就不能满足要求了,这里讨论两种解决该问题的方法。
二元词索引,为了处理长度为2的短语查询,我们可以扩展我们的索引结构,将文档中每两个连续词都看成一个短语词项,并为其建立倒排记录表,这样我们就有了词典为二元词项的倒排索引。
如果短语中的词项个数超过两个,可以简单的将其拆分成由AND连接的多个二元查询,比如 ( A B C ) (A\ B\ C) (A B C)可以拆分成 ( A B A N D B C ) (A\ B\ AND\ B\ C) (A B AND B C),但是这种方法存在的一个问题就是可能会有错误的返回结果。
二元词索引可以扩展到个更长的词序列,随之而来的问题就是我们的倒排词典可能会变得非常大,实际上当长度为2的时候词典的规模已经比原来大了很多。
很显然,二元词索引并不能真正解决短语查的问题,实际中更常用的是位置信息索引,顾名思义,就是将此项出现的位置信息存储在此项的倒排记录表中,形式为:文档ID:(位置1,位置2)。为了方便计算此项权重,我们往往也会将此项的频率写进倒排记录表。如下图所示:
![](https://github.com/serryuer/blog-img/raw/master/imgs/信息检索导论1/Snipaste_2019-05-03_03-06-33.png)
为了处理短语查询,在前面提到的倒排记录表合并算法的基础上,我们不仅仅要考虑词项是否出现,还要考虑其出现的位置。
采用位置索引会大大增加倒排记录表的存储空间,也会提高倒排记录表合并的复杂度。
一个混合策略是:对某些查询使用短语索引或者只使用二元词索引,而对其短语查询使用位置索引。短语索引所收录的那些较好的查询可以通过分析日志得到,往往是那些高频常见的查询,或者是处理开销比较大的查询,比如这样一些短语,它们中的每一个词都很常见,但是组合起来却很少见。
3. 词典及容错式检索
在介绍正式内容之前,我们先了解一下词汇表的两种存储结构:哈希表和搜索树。哈希表将每一个词项映射成一个整数,为了减少碰撞,需要足够大的目标空间,查询词项稍有变化都会导致哈希结果完全不同,因此哈希表的存储方式不能处理前缀查询。搜索树能够解决上面的大部分问题,它支持前缀搜索,最为出名的就是二叉树,每个内部节点都代表一个二值测试,测试结果用于确定下一步应该搜索的子树,二叉树高效搜索的关键是树的高度,即树的平衡性,因此在对二叉树进行增删的同时要进行平衡化处理。
在上面的介绍中,我们已经可以处理一般的布尔查询和邻近查询(即短语查询),有的时候我们对需要查询的词项的拼写形式没有绝对的把握,这个时候就需要通配符查询,类似于 ( a ∗ b ) (a*b) (a∗b),查询以a开头以b结尾的词项相关的信息。
除此之外,有的时候我们的查询可能出现拼写错误,导致精确查询没有返回结果,我们的检索系统应该能够对这类错误有一定的鲁棒性。
最后,我们会在普通的倒排索引的基础上介绍一些扩展之后的倒排索引。
3.1 通配符查询
我们首先看一种比较简单的形式, ( a ∗ ) (a*) (a∗),即通配符出现在尾部,这种查询称为前缀式查询,基于搜索树的词典结构对于处理这种查询来说非常方便。同样的,如果通配符出