搜索引擎系统工作原理 阅读笔记 | 青训营笔记

200 阅读7分钟

搜索引擎系统工作原理 阅读笔记

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

原文地址:搜索引擎背后的经典数据结构和算法developer.aliyun.com/article/765…

搜索引擎系统工作原理

image.png

1. 搜集

爬虫。从一组优质种子网页开始进行爬取,不断广度优先遍历加入待爬取队列,再不断地从待爬取队列里提取出 url 进行爬取。(可以启动多个爬虫并行爬取,这样速度会快很多)

  • 待爬取的 url 实现

    可以把待爬取的 url 放到 Redis 里,保证了高性能,需要注意的是,Redis 要开启持久化功能,这样支持断点续爬,如果 Redis 挂掉了,重启之后由于有持久功能,可以从上一个待爬的 url 开始重新爬

  • 判重,避免网页重复爬取

    哈希表占用空间太大(原文中有估算存储10亿 url所用哈希表大小的过程)

    所以采用布隆过滤器,可以大大减小占用内存。

    布隆过滤器可能会存在误判的情况,即某个值经过布隆过滤器判断不存在,那这个值肯定不存在,但如果经布隆过滤器判断存在,那这个值不一定存在,针对这种情况我们可以通过调整布隆过滤器的哈希函数或其底层的位图大小来尽可能地降低误判的概率,但如果误判还是发生了呢,此时针对这种 url 就不爬好了,毕竟互联网上这么多网页,少爬几个也无妨。

  • 网页存储文件:doc_raw.bin

    若一个网页存一个文件,因为这样10 亿个网页就要存 10 亿个文件,一般的文件系统不支持。

    所以一般是把网页内容存储在一个文件(假设为 doc_raw.bin)中,一个文件超过单个文件大小的限制时就再新建一个文件。

    image.png

    其中网页id的获取方式:一个 url 对应一个网页 id,所以我们可以增加一个发号器,每爬取完一个网页,发号器给它分配一个 id,将网页 id 与 url 存储在一个文件里,假设命名为 doc_id.bin:

    image.png

2. 预处理

我们拿到的是网页的 html 代码,需要把 <script>, <style>, <option> 这些无用的标签及标签包含的内容给去掉。

要删除自然需要先查找这些标签,怎么查找:

  • 法一:BF ,KMP 等算法。不过这些算法属于单模式串匹配算法,查询单个字段串效率确实不错,但无法一次性查出

  • 法二:AC 自动机多模式串匹配算法,可以高效一次性找出几个待查找的字段串,时间复杂度接近 0(n)

3. 分词并创建倒排索引

分词就是将一段文本切分成一个个的词。

  • 英文分词相对比较简单,只要以空格为分隔符切割字符串基本可达到分词效果

  • 但中文词与词之间没有空格等字符串分割,比较难以分割。一般是根据现成的词库来进行匹配,比如词库中有「中国」这个词,用处理过的网页文本进行匹配即可。当然在分词之前我们要把一些无意义的停止词如「的」,「地」,「得」先给去掉。

    中文分词可以用一些分词开源库。比如github 上有名的 jieba 分词开源库,它有全模式、精确模式、新词识别、搜索引擎模式几种分词模式。

分词后就可以得到各个分词与其所在网页id的关系,比如:

image.png

不同的网页内容有可能出现同样的分词,所以我们把具有相同分词的网页归在一起,比如:

image.png

这样我们在搜「大学」的时候找到「大学」对应的行,就能找到所有包含有「大学」的网页 id 了。

为了快速找到某个词对应的行(行里有所有包含这个词的网页id),会建立倒排索引

「分词」+「倒排索引」的处理流程,就是 ElasticSearch 搜索引擎干的事,也是 ES 能达到毫秒级响应的关键!

4. 查询

  • 用户输入关键词后,首先肯定是要经过分词器的处理。比如我输入「中国人民」,假设分词器分将其分为「中国」,「人民」两个词,接下来就用这个两词去倒排索引里查相应的文档,得到网页 id 后,我们分别去 doc_id.bin,doc_raw.bin 里提取出网页的url和内容,按权重从大到小排列即可。

    这里的权重和 PageRank 算法有关,还与另一个TF-IDF算法有关

    我们在 Google 上搜索一般在第一页的前几条就能找到我们想要的答案。这涉及到搜索引擎涉及到的另一个重要的算法: PageRank,它是 Google 对网页排名进行排名的一种算法,它以网页之间的超链接个数和质量作为主要因素粗略地分析网页重要性以便对其进行打分。PageRank 的计算需要用到大量的数学知识,此算法是 Google 的立身之本。

  • 另外在搜索框输入搜索词的时候,底下会出现一串搜索提示词,比如:

    image.png

    这是用Trie 树来实现的。Trie 树又叫字典树、前缀树(Prefix Tree)、单词查找树,是一种多叉树结构,如下图:

    image.png

    一般搜索引擎会维护一个词库,假设这个词库由所有搜索次数大于某个阈值(如 1000)的字符串组成,我们就可以用这个词库构建一颗 Trie 树。

    这样当用户输入字母的时候,就可以以这个字母作为前缀去 Trie 树中查找,以上文中提到的 Trie 树为例,则我们输入「te」时,由于以「te」为前缀的单词有 ["tea","ted","ted","ten"],则在搜索引擎的搜索提示框中就可以展示这几个字符串以供用户选择。

5. 寻找热门搜索字符串

Trie 树除了作为前缀树来实现搜索提示词的功能外,还可以用来辅助寻找热门搜索字符串,只要对 Trie 树稍加改造即可。假设我们要寻找最热门的 10 个搜索字符串,则具体实现思路如下:

一般搜索引擎都会有专门的日志来记录用户的搜索词,我们用用户的这些搜索词来构建一颗  Trie 树,但要稍微对 Trie 树进行一下改造,上文提到,Trie 树实现的时候,可以在节点中设置一个标志,用来标记该结点处是否构成一个单词,也可以把这个标志改成以节点为终止字符的搜索字符串个数,每个搜索字符串在 Trie 树遍历,在遍历的最后一个结点上把字符串个数加 1,即可统计出每个字符串被搜索了多少次(根节点到结点经过的路径即为搜索字符串),然后我们再维护一个有 10 个节点的小顶堆(堆顶元素比所有其他元素值都小)

依次遍历 Trie 树的节点,将节点(字符串+次数)传给小顶堆,根据搜索次数不断调整小顶堆(若比小顶堆的堆顶元素大,就把原堆顶元素删除,把新元素加入堆),这样遍历完 Trie 树的节点后,小顶堆里的 10 个节点即是最热门的搜索字符串。

总结:文中提到的算法/数据结构/技术

Redis,AC 自动机多模式串匹配算法,布隆过滤器,分词,倒排索引,PageRank算法,TF-IDF算法,Trie 树