机器学习基础——倒排索引与搜索引擎

今天的文章,我们继续探讨搜索引擎,和大家聊聊搜索引擎最重要的一环——倒排索引

在介绍倒排索引之前,我们先来看看什么是索引。索引是数据库当中的概念,维基百科中的说法是“数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据”。可以简单地把索引当成是字典里的检索目录,我们比如我们要查一个叫“index”的单词,通过目录,可以快速地找到字母i开始的位置。索引也是一样,不过我们查找的不再是单词的首字母,而是数据。

在之前介绍搜索引擎的文章当中,我们曾经说过,搜索引擎的爬虫爬取到网页的文本信息之后,会先进行分词,再进行存储。也就是说存储的不是完整的文档,而是文档当中的关键词信息。显然,搜索引擎当中包含的网页数量极为庞大,为了保证效率,我们必须要使用索引。

我们将每个网页称作是一个文档(document),为它准备一个文档Id,然后通过链表将文档当中的关键词串联起来。那么这个数据结构应该变成下面这个样子。

图片说明

在这张图里面,我们通过文档的ID去查询文档当中包含的关键词信息。我们先查到对应的文档,再去查其中的id,这是一个符合我们日常思维的查询,所以被认为是一个“正向查询”。因此,这个索引结构被称为正向索引

但是只有正向索引是不够的,比如用户搜索“北京大学”,我们可以拿到“北京”和“大学”两个关键词。我们希望的是可以通过这两个关键词检索出对应的文档,在这个时候,我们是不知道文档Id的。也就是说这是一个反向的查询,用字典做比喻,我们希望通过单词去查询它在词典当中的位置。

在我们只有正向索引的情况下,要做到这一点,我们必须遍历所有的文档,然后一一挑选出其中包含“北京”和“大学”关键词的文档。同样我们很容易明白,这是不可取的。所以为了解决这个问题,我们必须建立一个反向的索引,通过关键词指向文档。这样,我们就可以快速通过关键词筛选出对应的文档信息了。

这个反向的索引就是倒排索引

图片说明

有了倒排索引之后,剩下的就方便多了。我们就可以很方便地根据关键词召回所有含有关键词的文档,之后,再通过相应的算法计算各个文档与关键词之间的相关度,就可以进行相关性筛选了。这也是之前介绍搜索引擎的时候,提到的相关性过滤。

整个倒排索引的技术应该不难理解,不过实际操作的时候,要复杂一些, 还会涉及很多优化。下面就介绍众多优化方案当中,应用最广泛的一种。


ElasticSearch中的优化


说到倒排索引,不能不提ElasticSearch。ElasticSearch几乎可以说是全世界应用最广泛的开源搜索引擎了。从维基百科、GitHub再到百度、腾讯,以及无数的中小型公司,都离不开ElasticSearch的身影。它通过一套系统结合了搜索引擎、全文检索、结构化分析等众多功能,并且还有配置简单,性能出众等优点。

ElasticSearch身为分布式搜索引擎,巧妙的设计模式非常多,加上分布式系统本身的复杂性,可以研究的内容很多。今天这篇文章主要讲倒排索引,所以简单聊聊其中关于倒排索引的优化。

前文当中说了,我们通过对关键词设置倒排索引来达到关键词搜索的目的。从逻辑上看当然没有问题,但实际上问题不小。最大的问题就是这样的关键词实在是太多了,多还算了,而且这些关键词是没有顺序的,如果我们想要找到其中的某个,只能遍历所有的关键词表。这显然是我们不能接受的,这里必须要做优化。

一个最简单的优化就是对这些关键词进行排序,我们排序之后建立一个字典(dictionary)。有了dictionary之后,我们就可以通过二分查找一类的方式进行快速的搜索了。看似很完美,但还是有问题。

复杂度没有问题,O(logN)的复杂度是可以接受的,不能接受的是磁盘的读盘。因为这个dictionary实在是太大了,我们每次查找磁盘是需要开销的,每一次磁盘的随机读取需要消耗10ms的时间。对于一个高性能的系统来说,这同样是不能接受的。

我们要优化这个答案,就必须要减少磁盘的随机读取

想要减少使用磁盘,最好的办法就是把数据放在内存里。但是我们前面说了,这个dictionary太大了,内存里很有可能放不下。所以我们必须再对它做简单的索引,比如:

A字母开头的关键词存放在x页B字母开头的关键词存放在y页……

这其实就是查字典的方法,问题是如果关键词都是英文的,当然可以这么做。然而,搜索引擎并不仅仅支持英文,关键词可能是各种语言,甚至是各种符号。而且即使是英文的,每个字母对应的索引的数量也不是相同的。比如s字母开头的单词特别多,而z开头的就非常少。如果这样简单操作,其实并不一定能提升运行效率。

所以为了解决这个问题,我们需要引入一个数据结构,即前缀树(Trie树)

一棵前缀树大概长下面这个样子:

图片说明

前缀树的原理并不难,其实就是把前缀相同的字符串映射到树上的同一个分叉当中。每个分叉的末端记录的是这个前缀对应的内容的位置。其实也就是说将原本扁平化存储的索引,映射到了树上。不过,前缀树当中并不会存储所有的索引,只会存储关键词的一些前缀。通过前缀,我们可以找到dictionary当中的某个位置,之后再从这个位置开始往后顺序查找,如此就避免了过多使用硬盘的随机寻址,从而节省了时间开销。

用下图举个例子:

图片说明

比如我们要查找的关键词是“Access”,通过前缀树我们先查到A这个前缀对应的dictionary的位置,也就是图中的Ada的位置。之后我们从Ada往后顺序遍历,直到找到Access为止。通过合理地构建前缀树,我们可以控制遍历dictionary的开销,从而达到优化的目的。

除了这些之外,ElasticSearch还在联合索引的查询以及索引合并上做了一些优化。由于牵扯到一些其他的技术和数据结构,篇幅限制,这里不做过多赘述。会在之后的文章和大家分享。

如果觉得有所收获的,顺手点个关注吧~

图片说明

全部评论

相关推荐

02-05 08:18
四川大学 Java
在思考的熊熊很讨厌吃香菜:不是,我门头沟学院呢?这都没排上?
点赞 评论 收藏
分享
02-08 15:53
门头沟学院 Java
CoderEcho:让公司知道便宜没好货
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
正在热议
更多
# 听劝,这个简历怎么改 #
14116次浏览 183人参与
# 面试被问“你的缺点是什么?”怎么答 #
6486次浏览 100人参与
# 水滴春招 #
16657次浏览 370人参与
# 入职第四天,心情怎么样 #
11356次浏览 63人参与
# 租房找室友 #
8060次浏览 53人参与
# 读研or工作,哪个性价比更高? #
26200次浏览 356人参与
# 职场新人生存指南 #
199308次浏览 5519人参与
# 参加完秋招的机械人,还参加春招吗? #
27030次浏览 276人参与
# 文科生还参加今年的春招吗 #
4123次浏览 31人参与
# 简历无回复,你会继续海投还是优化再投? #
48639次浏览 561人参与
# 你见过最离谱的招聘要求是什么? #
144724次浏览 829人参与
# 如果重来一次你还会读研吗 #
155733次浏览 1706人参与
# 机械人选offer,最看重什么? #
69078次浏览 449人参与
# 选择和努力,哪个更重要? #
44330次浏览 494人参与
# 如果再来一次,你还会学硬件吗 #
103653次浏览 1245人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
20529次浏览 414人参与
# 招聘要求与实际实习内容不符怎么办 #
46804次浏览 494人参与
# 22届毕业,是读研还是拿外包offer先苟着 #
4654次浏览 27人参与
# 你们的毕业论文什么进度了 #
901356次浏览 8961人参与
# 软开人,你觉得应届生多少薪资才算合理? #
81380次浏览 496人参与
# 国企还是互联网,你怎么选? #
109200次浏览 853人参与
牛客网
牛客企业服务