gitbook/后端技术面试 38 讲/docs/190702.md
2022-09-03 22:05:03 +08:00

84 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 26 | 搜索引擎架构:如何瞬间完成海量数据检索?
我们在使用搜索引擎的时候搜索结果页面会展示搜索到的结果数目以及花费时间。比如用Google搜索中文“后端技术”这个词会显示找到约6.7亿条结果用时0.45秒。
![](https://static001.geekbang.org/resource/image/6d/43/6dee1fc91438b7974f734ff08ae4a343.png)
我们知道Google收录了全世界几乎所有的公开网页这是一个非常庞大的数目那么Google是如何做到在如此短的时间内完成了如此庞大的数据搜索呢
## 搜索引擎倒排索引
数据的搜索与查找技术是计算机软件的核心算法,这方面已有非常多的技术和实践。而对于搜索引擎来说,要对海量文档进行快速内容检索,主要使用的是倒排索引技术。
像Google这样一个互联网搜索引擎首先需要通过网络爬虫获取全球的公开网页。那么搜索引擎如何知道全世界的网页都在哪里呢
事实上,互联网一方面是将全世界的人和网络应用联系起来,另一方面,也将全世界的网页通过超链接联系起来,几乎每个网页都包含了一些其他网页的超链接,这些超链接互相链接,就让全世界的互联网构成了一个大的网络。所以,搜索引擎只需要解析这些网页,得到里面的超链接,然后继续下载这些超链接的网页,继续解析,这样就可以得到全世界的网页了。
这个过程具体是这样的。首先选择一些种子URL然后通过爬虫将这些URL对应的页面爬下来。其实所谓的爬虫就是发送URL请求下载相应的HTML页面然后将这些Web页面存储在自己的服务器上并解析这些页面的HTML内容当解析到网页里超链接URL的时候再检查这个超链接是否已经在前面爬取过了如果没有就把这个超链接放到一个队列中后面会请求这个URL得到对应的HTML页面并解析其包含的超链接……如此不断重复就可以将全世界的Web页面存储到自己的服务器中。
爬虫系统架构如下:
![](https://static001.geekbang.org/resource/image/ee/cd/ee3c796bf1897e3255f3edff47a7cacd.png)
得到了全部网页以后,需要对每个网页进行编号,得到全部网页的文档集合。然后再解析每个页面,提取文档里的每个单词,如果是英文,那么每个单词都用空格分隔,比较容易;如果是中文,需要使用中文分词器才能提取到每个单词,比如“后端技术”,使用中文分词器得到的就是“后端”、“技术”两个词。
然后考察每个词在哪些文档中出现比如“后端”在文档2、4、5、7中出现“技术”在文档1、2、4中出现这样我们就可以得到一个单词、文档矩阵
![](https://static001.geekbang.org/resource/image/4d/13/4db4adbeb66b2ece4022d394ed727613.png)
把这个单词、文档矩阵按照单词→文档列表的方式组织起来,就是倒排索引了:
![](https://static001.geekbang.org/resource/image/06/75/06f1dda3a1d2380370a60fbce1f17375.png)
我们这个例子中只有2个单词、7个文档。事实上Google数以万亿的网页就是这样通过倒排索引组织起来的网页数量虽然不可思议地庞大但是单词数却是比较有限的所以整个倒排索引的大小相比网页数量要小得多。Google将每个单词的文档列表存储在硬盘中而对于文档数量没那么大的应用而言文档列表也可以存储在内存中。每个单词记录下硬盘或者内存中的文档列表地址搜索的时候只要搜索到单词就可以快速得到文档地址列表。根据列表中的文档编号展示对应的文档信息就完成了海量数据的快速检索。
而搜索单词的时候我们可以将所有单词构成一个Hash表根据搜索词直接查找Hash表就可以得到单词了。如果搜索词是“后端”那么快速得到文档列表有4个如果搜索词是“后端技术”那么首先需要对搜索词进行分词得到“后端”、“技术”两个搜索单词分别得到这两个单词的文档列表然后将这两个文档列表求交集也很快可以得到搜索结果有两个。
虽然搜索引擎利用倒排索引已经可以很快得到搜索结果了,但是实践中,搜索引擎应用还会使用缓存对搜索进行加速,将整个搜索词对应的搜索结果直接放入缓存,以减少倒排索引的访问压力,以及不必要的集合计算。
## 搜索引擎结果排序
有了倒排索引虽然可以快速得到搜索结果了但是如果搜索结果比较多哪些文档应该优先展示给用户呢我们使用Google搜索“后端技术”的时候虽然Google告诉我们搜索结果有6.7亿个但是我们通常在搜索结果列表的头几个就能找到想要的结果而列表越往后结果也越不是我们想要的。Google是如何知道我们想要的结果是哪些呢这样的搜索结果展示显然是排过序的那搜索引擎的结果是如何排序的呢
事实上Google使用了一种叫PageRank的算法计算每个网页的权重搜索结果就按照权重排序权重高的网页在最终结果显示的时候排在前面。为什么权重高的网页正好就是用户想要看到的呢我们先看下这个网页权重算法即PageRank算法。
PageRank算法认为如果一个网页里包含了某个网页的超链接那么就表示该网页认可某个网页或者说该网页给某个网页投了一票。如下A、B、C、D四个网页箭头指向的方向就是表示超链接的方向B的箭头指向A表示B网页包含A网页的超链接也就是B网页给A网页投了一票。
![](https://static001.geekbang.org/resource/image/d2/f5/d2763103bd0b10d6c21dd70ea1c096f5.png)
开始的时候所有网页都初始化权重值为1然后根据超链接关系计算新的权重。比如B页面包含了A和D两个页面的超链接那么自己的权重1就被分成两个1/2分别投给A和D。而A页面的超链接包含在B、C、D三个页面中那么A页面新的权重值就是这个三个页面投给它的权重值之和1/2 + 1/3 + 1 = 11/6。
经过一轮PageRank计算后每个页面都有了新的权重然后基于这个新的权重再继续一轮计算直到所有的网页权重稳定下来就得到最终所有网页的权重即最终的PageRank值。
通常在一个网页中包含了另一个网页是对另一个网页的认可认为这个网页质量高值得推荐。而被重要网页推荐的网页也应该是重要的PageRank算法就是对这一设想的实现PageRank值代表了一个网页受到的推荐程度越受推荐越重要就越是用户想看到的。基于每个网页的PageRank值对倒排索引中的文档列表进行排序排在前面的文档通常也是用户想要看到的文档。
PageRank算法对于互联网网页排序效果很好但是对于那些用户生成内容UGC的网站而言比如豆瓣、知乎或者我们的[InfoQ](https://www.infoq.cn/)如果想在这些网站内部进行搜索PageRank算法就没什么效果了。因为豆瓣的影评知乎的回答InfoQ的技术文章之间很少通过超链接进行推荐。
那么要相对这些站内搜索引擎的结果进行排序就需要利用其它一些信息以及算法比如可以利用文章获得的点赞数进行排序点赞越多表示越获得其它用户的认可越应该在搜索结果中排在前面。利用点赞数排序或者PageRank排序都是利用内容中存在的推荐信息排序而这些推荐信息来自于广大参与其中的人因此这些算法实现也被称作“集体智慧编程”。
除了用点赞数进行排序有时候我们更期望搜索结果按照内容和搜索词的相关性进行排序比如我在infoq.cn搜索PageRank我其实并不想看那些点赞很多但是只提到一点点PageRank的文章而想看主要讲PageRank算法的文章。
这种情况可以使用词频TF进行排序词频表示某个词在该文档中出现的频繁程度也代表了这个词和该文档的相关程度。词频公式如下
![](https://static001.geekbang.org/resource/image/53/e3/53ba5cb404c5aa008db221fb106b0ee3.png)
使用豆瓣电影进行搜索的时候,豆瓣的搜索结果主要是电影名中包含了搜索词的电影,比如我们搜索“黑客”这个词,豆瓣的搜索结果列表就是以“黑客”为电影名的电影。
![](https://static001.geekbang.org/resource/image/9f/0b/9f23220ee088a22a4d2d198ffba2290b.png)
但是,如果我想搜索电影内容是关于黑客的,但是标题里可能没有“黑客”两个字的电影,豆瓣的搜索就无能为力了。几年前,我自己专门写了一个电影搜索引擎,利用豆瓣的影评内容建立倒排索引,利用词频算法进行排序,搜索的结果如下,这个结果更符合我对电影搜索引擎的期待。
![](https://static001.geekbang.org/resource/image/0b/c7/0b960049970ad13d26d2dd8d648108c7.png)
如果你对这个搜索引擎有兴趣,源代码的地址在这里:[https://github.com/itisaid/sokeeper](https://github.com/itisaid/sokeeper)
## 小结
事实上搜索引擎技术不只是用在Google这样的搜索引擎互联网应用中对于大多数应用而言如果想要对稍具规模的数据进行快速检索都需要使用搜索引擎技术。而对于淘宝这样的平台型应用搜索引擎技术甚至驱动其核心商业模式。一方面淘宝海量的商品需要通过搜索引擎完成查找另一方面淘宝的主要盈利来自于搜索引擎排名。所以本质上淘宝的核心技术和盈利模式跟百度、Google都是一样的。
## 思考题
文中我们讨论了PageRank算法如果只有几百个网页那么写一个程序计算每个网页PageRank就可以了但是如果是Google这样万亿级的网页网页之间的超链接关系数量更加庞大而PageRank算法又需要多轮计算如何才能较快地计算出所有网页的PageRank值呢
欢迎你在评论区写下你的思考,也欢迎把这篇文章分享给你的朋友或者同事,一起交流一下。