【简记】大规模Web开发技术(第九章)

来源:互联网 发布:先导爱知在g出现吗 编辑:程序博客网 时间:2024/06/07 14:00

第九章主题——挑战全文搜索技术(大数据处理技巧)

第24课 全文搜索技术的应用范围

本次首先从Hatena 实际应用的搜索引擎概要开始,接着讲述创建搜索引擎中最重要的元素之一一逆向索引( inverted index) 。逆向索引由Dictionary (字典文件)和Postings (置入文件)两个基本要素组成。本章的目标是以逆向索引为基础,理解搜索引擎的基本结构。


“包含某关键字文章”实现的技术改进:

before:利用关系型数据库,缺点是当记录数太多,就会在可扩展性上出现问题。

after:利用搜索技术呈现。系统核心代码用C++实现,使用thrift 库与Perl 前端进行通信。


第25课 搜索系统的架构

搜索系统所需的步骤

①爬行(获取大量文档)
②存储(将文档保存,涉及到分布式数据库)

③建立索引
④搜索
⑤评分(返回最相近的网页)
⑥显示结果


想深入研究的人,可以参考课程中多次提及的Introduction to Information Retrieval,书中有详细的解释。这本书曾经作为斯坦福大学的教科书。

本章主要介绍3和4环节。


全文搜索的种类

全文搜索从架构上看有很多种。本次讨论" grep 类型" "后缀类型" "逆向索引类型" 三种。


grep类型:

grep 类型就是将搜索对象文档全部读出,说起来算是最单纯的架构。全部读入之后,就能找到匹配的文档了。比如第8 章的课题中用Aho-Corasick 算法创建的自动机,也要将全部文档输入自动机,因此这种方法也可以分类到grep 类型。
这是相当朴素的方法,如果一板一眼地实现,那么假设搜索对象文本( text) 长度为m,要搜索的词语( word ) 长度为n ,那么复杂度就是O(mn) 。

教科书上讲过KMP算法和BM算法等,它们能在一定程度上改善复杂度。
但是不管哪一种,都要从头开始读取整个文档。可以想象,这种单纯的实现方法在数据量增加时会遇到麻烦。



另外, KMP 算法其实很像Aho-Corasick 算法。Aho-Corasick算法要输入一大堆搜索关键字,对吧。它将Hatena Keyword 的27 万条关键字全部作为搜索词,然后输入文档,但如果只有一个搜索关键字,那么跟KMP算法几乎是一样的,复杂度也大致相同。


grep的优点:

1.优秀的即时性。文档更新后立即就能搜索。

2.搜索不会被遗漏。

3.grep 类型的并行化也很简单。例如,要在特别长的文档中搜索,可以将文档分割后并行搜索,或者像Aho-Corasick算法那样把要搜索的单词构成自动机,并将文档输入,就能同时搜索多个关键字。


后缀类型:

这种类型用可搜索的形式存储搜索对象全文。数据结构有Trie 、Suffix Array 、SUfflX Tree 等。
限于篇幅,这里就不再详细介绍各个数据结构,粗略来说就是用可搜索的形式将文档全部存储到内存中。与后文要讲的逆向索引相比,不同点是逆向索引需要保存文档副本,后缀类型则不需要。


后缀类型出现的目的就是快速搜索。但是,第8 章的课题中我们己看到, Trie 创建的数据量很大。由于信息量很大,因此即使理论上搜索可行,这种架构的引擎也很难实现。


逆向索引类型:

主流。简单来说,逆向索引就是将单词( term) 与文档关联的产物。

其特征是,逆向索引方法必须在文档之外另行创建逆向索引。也就是说,搜索之前要预先创建逆向索引。因此,它无法实现grep 那种文档更改后立即反映到搜索结果中。


第26课 搜索引擎的内部结构

逆向索引的结构——dictionary+postings



1是五个文档,2中左侧是dictionary,右侧是postings,即关键词(term)所在的文档,两者构成逆向索引。


Dictionary的创建


将单词用作term处理:

①字典+Aho-Corasick 算法

需要有作为字典的数据(Wikipedia词条或者用户自定义)

②使用语素分析(将语素看成单词,变为term 使用)



将n-gram作为term 处理:

n-gram 也称为k-gram o n-gram 就是对文本每n个字进行切分。例如, abracadabra 的3-gram 就是abr 、bra 、rac . .等等。
虽说是每3 个字切分,但abr 之后并不是aca ,而是bra 。能理解吗?每次移动一个字,并切分出3 个字,即abra→abr 和bra 。
上例为3 个字,写成3-gram 或tri-gram。还可以将abra 以两个字为单位拆成ab 、br、ra,称为2-gram 或bi-gramo
可以将n-gram 的切分结果作为term 创建Dictionary 。


用同样的规则切分查询
用n-gram 创建Dictionary ,那么查询也要用同样的规则切分。搜索"はてな"时,要将查询分割成"はて"和"てな"。用这两个词在逆向索引中搜索,可得两个Postings 。同时包含在这两个Postings 中的文档编号就是包含"はてな " 的文档。用求集合交集的操作即可获得同时包含在两个Postings 中的文档编号。用英文说就是" intersection " 。(这里有疑问,同时包含两个分词,不代表就有两个分词组成的词吧?)


为避免上面括号中提出的问题,需要在得到搜索结果后利用过滤。即在得到搜索结果后,要进行全文遍历。

缺点(过滤时发生):但如果搜索结果过大,搜索时间就相当于之前的grep,从而产生各种问题。


Hatena Bookmark对实际情况进行了分类

1.搜索标题、评论、URL时,用n-gram逆向索引不会产生遗漏,而且这三类长度较小,过滤也简单。

2.正文,采用单词逆向索引


查全率和查准率


标准称为查全率(Recall )和查准率( Precision )。这个标准用于评价搜索的恰当性, 查全率表示返回结果的量,查准率表示搜索结果中是否包含相关结果。


A 是搜索结果,B 是搜索系统中潜在的相关文档,C是搜索结果中的相关结果。


查全率就是说,所有文档中有一部分包含"Hatena",搜索引擎能返回其中的多少。例如整个系统中有1000 个文档包含" Hatena " ,搜索"Hatena"时能返回其中的多少个文档。

查准率就是说返回的结果中包含多少正确结果。返回的大量搜索结果中可能包含错误的结果,也就是完全不相干的结果。如果不相干结果太多, C 的部分就会变小,查准率就会下降。


以语素分析和n-gram为例,语速分析会有该命中却不命中的现象,但很少返回意料之外的结果;n-gram很少发生搜索遗漏,但会返回意想不到的结果。


Postings的创建

创建Postings 的方法也有很多。上例中仅仅保存了文档ID ,但有时还要保存term 在文档内的出现位置,这种情况也称为"Full Inverted Index" 。保存出现位置,就可以显示snippet,从而立即获知单词包含在文档的什么位置。


这对于评分也有很大帮助。比如,用"Hatena" 和"京都"以and 搜索时,希望得到Hatena 与京都有关的话题。在这种情形下,从感觉上讲, " Hatena "和"京都"两个单词应该出现在相近的位置。例如"Hatena 公司位于京都"这篇文档。要在评分时考虑、"单词位置接近"一一即单词的接近程度,就要用到单词的出现位置。Google 应该也是这样做的。


此外它还有助于在使用n-gram 时进行过滤。两个单词处于相邻位置的话,这个搜索结果就肯定没错了。




本次实现只保存ID 不保存出现位置的Postings

这样看来,所谓逆向索引,其左侧是term,右侧是压缩过的文档ID 的列表(Postings List) ,是个key-value (键值〉结构。
在Perl 中就是散列的key 与散列的valueo 因此,它更适合采用key-value 存储。


评分

Google 最初采用的方法是,用以前的搜索历史衡量文档的重要性,并据此排名。

刚才说过的考虑两个搜索关键字的出现位置等,还有其他各种算法,都被用于确定搜索结果排名。

为确定搜索结果的顺序,人们想出了各种方法,例如计算搜索关键字在文档中的重要性,可以假设"Hatena" 这个单词在文档中的重要度较高,就提高文档的排名。此时还可以用TF/IDF作为指标。还有就是搜索关键字集合,给出大量搜索关键字时,可以检查搜索对象文档所包含的单词序列,判断文档与给定的关键字序列是否相似等。


----------------------------------------


阅读全文
0 0