布尔检索及其查询优化

         针对布尔查询的检索,布尔查询是指利用AND,OR或者NOT操作符将词项连接起来的查询。

        举个简单的例子:莎士比亚的哪部剧本包含Brutus及Caesar 但是不包含Calpurnia?布尔表达式为:Brutus AND Caesar AND NOTCalpurnia。最笨的方法是线性扫描的方式:从头到尾扫描所有剧本,对每部剧本判断它是否包含Brutus和Caesar ,同时又不包含Calpurnia。这个方法缺点如下:速度超慢(特别是大型文档集)、处理NOT Calpurnia 并不容易(一旦包含即可停止判断)、不太容易支持其他操作(例如find the word Romans nearcountrymen)、不支持检索结果的排序(即只返回较好的结果)。

        一种非线性扫描的方式是事先给文档建立索引(index),假定我们对每篇文档(这里是剧本)都事先记录它是否包含词表中的某个词,结果就会得到一个由布尔值构成的词项—文档关联矩阵,如下图:


         为响应查询Brutus AND Caesar AND NOTCalpurnia,我们分别取出Brutus、Caesar及Calpumia 对应的行向量,并对 Calpumia对应的向量求反,然后进行基于位的与操作,得到: 

110100 AND110111 AND 101111 = 100100

结果向量中的第1和第4个元素为1,这表明该查询对应的剧本是Antonyand Cleopatra和Hamlet。

        检索效果的评价标准一般为 正确率召回率。正确率(Precision)表示返回结果文档中正确的比例,如返回80篇文档,其中20 篇相关,正确率1/4;召回率(Recall)表示全部相关文档中被返回的比例,如返回80篇文档,其中20 篇相关,但是总的应该相关的文档是100篇,召回率1/5。正确率和召回率反映检索效果的两个方面,缺一不可。全部返回,正确率低,召回率100%,只返回一个非常可靠的结果,正确率100%,召回率低。因此引入了 F度量,如下:


        回到刚才的例子,我们显然不能再采用原来的方式来建立和存储一个词项—文档矩阵,假定N = 1百万篇文档(1M), 每篇有1000个词(1K),每个词平均有6 个字节( 包括空格和标点符号),那么所有文档将约占6GB 空间,假定词汇表的大小( 即词项个数)为50万,即500K,则词项—文档矩阵=500K x 1M=500G。我们可以对上述例子做个粗略计算,由于每篇文档的平均长度是1000个单词,所以100万篇文档在词项—文档矩阵中最多对应10亿(1 000×1 000 000 )个1,也就是在词项—文档矩阵中至少有99.8%(1 - 10亿/5000亿)的元素为0。很显然,只记录原始矩阵中1 的位置的表示方法比词项—文档矩阵更好。

         上述思路就引出了倒排索引。对每个词项t,记录所有包含t的文档列表,每篇文档用一个唯一的docID来表示,通常是正整数,如1,2,3...通常采用变长表方式来存储docID列表。倒排索引如下图:


        注意,词典部分往往放在内存中,而指针指向的每个倒排记录表则往往存放在磁盘上。词典按照字母顺序进行排序,而倒排记录表则按照文档ID号进行排序。倒排索引的构建过程如下图:


        索引构建过程如下:文档生成词项——词项排序——合并,如下三幅图:




考虑如下查询:Brutus AND Calpurnia,步骤如下:

(1)在词典中定位Brutus ;

(2)返回其倒排记录表;

(3)在词典中定位Calpurnia ;

(4)返回其倒排记录表;

(5)对两个倒排记录表求交集,如下图所示:


上述合并算法的伪代码描述如下:


       下面考虑查询优化的问题,查询优化(query optimization )指的是如何通过组织查询的处理过程来使处理工作量最小。对布尔查询进行优化要考虑的一个主要因素是倒排记录表的访问顺序。一个启发式的想法是,按照词项的文档频率(也就是倒排记录表的长度)从小到大依次进行处理,如果我们先合并两个最短的倒排记录表,那么所有中间结果的大小都不会超过最短的倒排记录表,这样处理所需要的工作量很可能最少。如下图,就是先计算两个短的倒排记录表的and运算。


         对于任意的布尔查询,我们必须计算并临时保存中间表达式的结果。但是,在很多情况下,不论是由于查询语言本身的性质所决定,还是仅仅由于这是用户所提交的最普遍的查询类型,查询往往是由纯“与” 操作构成的。在这种情况下,不是将倒排记录表合并看成两个输入加一个不同输出的函数,而是将每个返回的倒排记录表和当前内存中的中间结果进行合并,这样做的效率更高而最初的中间结果中可以调入最小文档频率的词项所对应的倒排记录表。该合并算法是不对称的:中间结果表在内存中而需要与之合并的倒排记录表往往要从磁盘中读取。此外,中间结果表的长度至多和倒排记录表一样长,在很多情况下,它可能会短一个甚至多个数量级。在倒排记录表的长度相差很大的情况下,就可以使用一些策略来加速合并过程。对于中间结果表,合并算法可以就地对失效元素进行破坏性修改或者只添加标记。或者,通过在长倒排记录表中对中间结果表中的每个元素进行二分查找也可以实现合并。另外一种可能是将长倒排记录表用哈希方式存储,这样对中间结果表的每个元素,就可以通过常数时间而不是线性或者对数时间来实现查找。



参考:

信息检索导论——ChristopherD. Manning等著

中科院-现代信息检索ppt——王斌

你可能感兴趣的:(文本挖掘)