The Anatomy of a Large-Scale Hypertextual Web Search Engine

The Anatomy of a Large-Scale Hypertextual Web Search Engine

这篇文章的原文在: http://infolab.stanford.edu/~backrub/google.html

这是一篇分析大规模文本搜索引擎的文章,分析的是google的搜索引擎,除了传统的搜索引擎应用到大规模数据的问题,本文还介绍了新的技术挑战包括利用超文本的附加信息生成更好的搜索结果,同时,本文还关注如何有效处理任意人随意发布任何信息的超文本数据集。

1. 简介
搜索引擎技术不得不经常调整以跟上网络的增长。创建搜索引擎遇到了多种挑战:快速的爬虫技术被用来收集最新的web文档;有效的存储空间被用来存储文件的索引和文档。这就要求索引系统能够容纳大据量,并且查询能够快速处理。随着网络的增长,这项工作变得越来越困难,硬件性能和费用问题的改善虽然部分削减了困难度,但是诸如磁盘寻道时间和操作系统的健壮性问题依然存在。

2. 系统特性
Google搜索引擎有两个重要的特性,有助于产生高精度结果。第一,它利用网络的链接结构来计算网页的排名值,称为PageRank;第二,Google利用链接来改进搜索结果。
计算PageRank:
PageRank并非对指向网页的链接平等的计数,而是将链接数标准化。我们假如有网页 T1...Tn指向网页A,指数d是0到1之间的抑制因子( damping factor),通常设为0.85。同时C(A)定义为从网页A指出的链接数。网页A的PageRank值如下:
PR(A) = (1-d) + d(PR(T1) / C(T1) + ... + PR(Tn) / C(Tn))
注意,所有的PageRank再各网页中形成概率分布,所以所有网页的PageRank的和会是1.
链接文本
我们把它和这个链接所指向的网页关联起来。这样做有两点好处。首先,链接文本往往能比网页本身提供更精确的描述。其次,对于基于文本的搜索引擎不能索引的文档,比如图像、程序、数据库等,链接文字是有必要存在的。
3. 相关工作
这里就不再赘述
4.系统剖析
首先,我们对体系结构做一个整体的讨论。然后,会对深层次的重要的数据结构做一些描述。最后,我们会逐个深刻解释主要的应用程序:爬行器,索引器和搜索器。
4.1 Google体系结构概述 

图1 Google整体架构

在Google中,网络爬行(网页的下载)是由很多分布的爬行器( crawlers)来做的。由一个URL服务器( URLserver)来向爬行器发送URL列表。被抓取下来的网页就被送到存储服务器( store server)上。存储服务器再把网页压缩并存储在仓库( repository)里。每一篇网页都有唯一一个与之相关联的ID号,称作docID,每当有一个新的URL被分析出来的时候都会被赋予一个docID。索引函数由索引器( indexer)和整理器( sorter)在执行。索引器会执行若干个函数。它会读取仓库、解压文档并分析它们。每一篇文档都被转化为词汇出现情况的集合,被称为hits。hits记录了词汇、在文档中的位置、对字号的估计和大小写。索引器将这些hits分发到一些“桶”( barrels)的集合中,创建部分整理好的前向索引。索引器还要执行另一个重要的函数。它要分析出每一篇网页中的链接然后将关于它们的重要信息存储在一个链接( anchors)文本文件中。这个文件包含了足够的信息,可以判断每个链接分别是从哪里到哪里,还有链接上的文本。
URL分解器( URLresolver  )读取链接文件( anchors),并将其中相对URL转化为绝对URL,然后转化成docID。它将链接文本放入前向索引中,将链接所指向的docID与之关联起来。它还要生成一个docID键值对的链接数据库( links)。链接数据库是用来给所有文档计算PageRank的。
整理器( sorter)获得以docID整理过的桶( barrels),再根据docID进行整理,生成倒排索引。为了使这个操作几乎不需要临时空间,这一步要在一个特定的地方执行。整理器在倒排索引中产生wordID和偏移量的列表。一个叫DumpingLexicon的程序将这个列表和由索引器生成的词典( lexicon)比较构造出搜索器所用的新词典。搜索器由网络服务器运行,利用由DumpingLexicon构造的词典和倒排索引还有PageRank来回应查询。

4.2 主要的数据结构
 4.2.1. BigFiles
BigFiles是跨越多个文件系统的虚拟文件,可由64位整数寻址。在多文件系统之间空间分配是自动处理的。BigFiles包还可以处理文件描述符的空间分配和回收,因为操作系统提供的功能不够我们用的。BigFiles还支持基本的压缩选项。
4.2.2. Repositity
仓库包含了所有的网页的HTML全文。每一页都用zlib(见RFC1950)压缩。在仓库中,文档一个接一个地存储,用 docID、长度和URL做为前缀,如图2。访问仓库不需要其它的数据结构了。这样有助于保持数据的一致性并且能显著简化开发工作;我们可以通过仅仓库和一个爬行器错误文件来重建所有其它的数据结构

图2 仓库的数据结构

4.2.3 Document Index

文档索引保留了每个文档的信息。它是一个定宽ISAM(Index sequential access mode)索引,以docID排序。其中每一项中的存储的信息包括了当前文档状态、指向仓库的指针、文档的校验和还有各种统计数据。如果一篇网页被抓取过,那它同时也会包括一个指针,指向一个变长的含有它的URL和标题的文件,这个文件被成为docinfo。否则这个指针就指向一个只含有URL的URL 列表。这样的设计选择是因为我们希望有一个简洁的数据结构,并且能够在一次查询中只访问一次磁盘就得到一条记录。
另外还有一个文件用来将URL转换为docID。文件中是URL的校验和与对应docID的列表,并且以校验和排序。要找到某个特定的URL的 docID,先计算出URL的校验和,再在校验和文件中做二分查找就能找到它的docID了。通过于这个文件的合并可以将URL批量转换成docID。这种技术被URL分解器用来将URL转换成docID。而批量转换的改进是至关重要的,因为否则我们就必须对每一个链接进行一次磁盘寻道。
4.2.4 Lexicon
词典有几种不同的形式。与以前的系统相比一个重要的变化是词典可以被放在内存中而不会在内存上花费很多。在现在的实现中我们可以将词典放在一台256M内存的机器上。目前的词典含有1千4百万词汇(虽然有一些罕见的词汇没有被放进去)。它的实现分两部分: 一个词汇的列表(连接在一起但是用null分隔)和一个指针的散列表。对不同的函数,词汇列表有一些辅助信息,完整的讨论已经超出了本文的范围。
4.2.5 Hit Lsts
一个hit列表对应于一个特定的词汇在一个特定的文档中出现情况,包括了位置、字号、大小写等信息。Hit列表在前向索引和倒排索引中占了大部分空间。因此,使它们的表现形式尽量有效率很重要。我们考虑了几种可选的方案来对位置、字号和大小写信息进行编码——简单编码(用三个整数),紧凑编码(用手工优化的比特分配),和哈夫曼编码。最后我们选择了手工优化的紧凑编码,因为它占用的空间远小于简单编码,而对比特的操作也远少于哈夫曼编码。Hit的细节见图 3。  

我们的紧凑编码每个hit使用两个字节。有两种类型的hit:特别hit与普通hit。特别hit包括了出现在URL、标题、链接文本或者元标签中的 hit。普通hit指所有其它的hit。普通hit包括了一个大小写位、字号、和12比特的词汇在文档中的位置。
4.2.6 Forward Index
前向索引实际上已经部分地排好序了。它被存储在一定数量的桶里(我们用了64个)。每个桶里维护这一定范围的wordID。如果一篇文档的的词汇落在了某个桶里,这篇文档的docID也被存储在桶里,后跟wordID的列表和与这些词对应的hit 列表。这种方案因为重复存储docID而需要更多的存储空间,但是在由于桶很多所以区别不大,且在整理器进行最后的索引操作的时候能够节省相当多的时间和降低编码复杂度。更进一步地,我们并非存储wordID本身,而是存储该wordID与所在桶最小wordID的相对位置。这样,我们就可以只将24比特用于未排序的桶里的wordID,留下8比特给hit列表的长度字段。 
4.2.7 Inverted Index
倒排索引包含了和前向索引相同的桶,但是倒排索引已经被整理器处理过了。对于每一个有效的wordID,词典都包含了一个指向该词所在桶里的指针。它同时指向一个docID的doc列表和与之对应的hit列表。这个doc列表表示了一个词汇在所有文档中的出现情况。  一个重要的问题是在doc列表中docID应该以什么顺序存储。一个简单的解决办法是以docID排序。这样可以方便合并不同的doc列表从而支持多词查询。另一个选择是按照词汇在每篇文档中的出现情况排序存储。这样做使得回应单一词汇查询显得轻易而举了,还使对多词查询的结果都接近起始处。但是,这样使合并要麻烦得多。同时,这也让开发工作更困难,因为每当要改动排序函数都要重建索引。我们的选择是两者的折衷,同时维护两组倒排桶——一组用来存储含有标题或者链接文字的hit列表,另一个存储所有的hit列表。这样,我们先在检查第一组桶,如果这些桶里没有足够的匹配我们就查找大桶。

4.3 爬行网络
为了覆盖上亿篇网页,Google有一个快速的分布式爬虫系统。一台URL服务器给数台(我们一般运行三台)爬虫提供URL。URL服务器和爬虫都是用 Python实现的。每台爬虫一般同时维护300左右个的连接。只有这样才能使网页抓取速度有足够快的速度。在峰值速度下,四个爬虫的系统每秒钟能爬行上百篇网页。这就是说数据率在每秒600K左右。DNS解析是一个主要的性能瓶颈。每个爬虫都自己维护一个DNS缓存,这样就不必在爬取每篇文档前都去解析 DNS。上百个连接中的每一个都可能处于几种不同的状态中:DNS解析、连接主机、发送请求和接受回应。这些因素使得爬虫程序成为系统中的一个复杂的组成部分。它使用异步IO来处理事件,还要有许多队列来转换页面抓取的状态。

4.4 索引网络
分析——任何被设计为运行在整个网络上的分析器都必须能够处理大量可能出现的错误。范围从HTML标签的打字错误到标签之间几K字节的零、非ASCII码字符、上百层的HTML标签嵌套,还有些超出任何人想象的各式各样的和解决办法一样多的错误会出现。为了得到最快速度,我们没有采用YACC生成上下文无关文法分析器,而采用了flex生成的词汇分析器,它只需要配有自己的堆栈。开发这样一个快速并且健壮的的分析器需要极大的工作量。  

将文档索引到桶中——在分析完每一篇文档后,它都被编码放进一些桶中。每个词都被一个内存中的散列表——词典转化成wordID。有新词加入词典散列表时,会记录到日志文件中。一旦词汇都被转化为wordID后,它们在当前文档中的出现情况就会被转换成hit列表并被写入到正排桶中。索引阶段并行性的主要困难是词典需要被共享。我们没有共享词典,而是致力于对所有不在基础词典中的额外词汇写到日志中,我们的基础词典中有1千4百万条词汇。这样多个索引器就能并行运行,那个小日志文件可以由最后一个索引器来处理。  

整理——为了产生倒排索引,整理器将每个正排桶按照wordID排序并分别为标题、链接、和全问生成倒排桶。一次只有一个桶被处理,所以它需要的临时存储空间很少。另外,我们将排序步骤并行化,我们只要简单的运行多个整理器就能尽可能地用上所有的机器,这样就能同时处理多个桶。因为桶太大没法装到内存里去,所以整理器进一步地将它们细分为一些基于wordID和docID能放进内存里的篮筐。然后整理器将每个篮筐装载到内存里来,将它排序,把其中内容写入到短倒排桶和全文倒排桶里去。

4.5 搜索  
搜索的目的是高效地提供高质量的结果。很多商业搜索引擎似乎在效率方面有不小的进步。Google查询评价的过程如表4。 


4.5.1 排序系统
Google比一般的搜索引擎对网络文档维护了更多的信息。每一个hit列表包含了位置、字体和大小写信息。另外,我们还考虑了链接文字里的hit和文档的PageRank的影响。在排序中综合考虑这些信息是很困难的。我们对排序函数设计是没有那个因素的影响过大。首先考虑最简单的情况——单一词汇的查询。为了给单一词汇查询中的一篇文档评级,Google先在这篇文档的hit列表找到中那个词。Google假设每一个hit都属于某种类型(标题、链接、URL、大字号普通文本、小字号普通文本……),每种类型都有自己的权重。这些权重构成了一个由类型索引的向量。Google将hit列表中每种类型的hit计数。然后将计数值转换为计数-权重。计数-权重先随着计数值线性增长但是很快就停止增长了,计数超过某个值时就与计数没有关系了。我们将计数-权重与类型-权重向量的内积作为该文档的IR得分。最后,由结合IR和分和PageRank给出该文档最后的评级。  

对于多词查询,情况就复杂多了。多个hit列表必须同时扫描,才能使同一文档中相邻的hit的权值比离得远的hit的权值高。分布在不同hit列表中的 hit分开匹配,以便相邻的hit一起匹配。对于每个匹配hit集,都要计算一个邻近度。这个邻近度基于hit在文档(或者链接)中的距离计算,但是被分为十个等级,范围从短语匹配到“毫不相干”。我们不仅对每种类型的hit计数,而且还对每种类型和邻近度计数。计数被转换成计数-权重,然后我们取计数-权重和类型—邻近度—权重的内积计算IR得分。所有这些数和矩阵都可以在一种特殊的调试模式下被显示出来。这些显示输出对排序系统的开发工作大有帮助。

4.5.2 反馈  
排序函数有许多象类型-权重和类型-近似值-权重这样的参数。从这些参数重得出正确的结果就像在暗箱操作。为了达到目的,我们的搜索引擎重带有用户反馈机制。可信的用户可以对所有返回结果进行有选择的评价。反馈信息被保存下来。然后当我们修改排序函数的时候就能看出这种改变在以前排好序的搜索上的影响。虽然远不是那么完美,但是这能让我们了解排序函数中的改变会如何影响结果。 

5 结果和性能
所有这些结果的质量都是相当高的,最后检查,没有一个是死链。这很大程度上是因为它们的PageRank值都很高。PageRank值由条中的红色部分的百分比表示


5.1 存储需求  
除了搜索质量以外,Google的设计使之能够随着网络的增长而有效地调整成本。这其中就包括了存储效率方面的问题。表1列出了一些统计结果和 Google的存储需求。由于应用了压缩计数,仓库的总大小大约是53G,是实际要存网页大小的三分之一多一点。按照当前的磁盘价格来看,仓库成为了成本低廉,有用的数据源。更重要的是,搜索引擎所需全部数据的总大小也是差不多的,大约55G。而且,多数查询只需要用到短倒排索引。有了文件索引优化的编码和压缩方式,一个高质量的搜索引擎就能在一台7G磁盘的新PC上运行了。



















  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值