检索技术核心 20 讲
陈东
前数禾科技 CTO,前奇虎 360 商业化资深总监
21492 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 29 讲
检索技术核心 20 讲
15
15
1.0x
00:00/00:00
登录|注册

05 | 倒排索引:如何从海量数据中查询同时带有“极”和“客”的唐诗?

将关键字作为key插入哈希表
解析当前文档中的每个关键字,生成<关键字,文档ID,关键字位置>这样的数据对
给每个文档编号,作为其唯一的标识,并且排好序
将一个文档解析并加入倒排索引
倒排索引
哈希表存储所有诗
链表归并提取公共元素例子
步骤
倒排索引
正排索引
课堂讨论
重点回顾
如何查询同时含有“极”字和“客”字两个key的文档
如何创建倒排索引
两个非常常见又非常重要的检索技术
如何从海量数据中查询同时带有“极”和“客”的唐诗?

该思维导图由 AI 生成,仅供参考

你好,我是陈东。
试想这样一个场景:假设你已经熟读唐诗 300 首了。这个时候,如果我给你一首诗的题目,你可以马上背出这首诗的内容吗?相信你一定可以的。但是如果我问你,有哪些诗中同时包含了“极”字和“客”字?你就不见得能立刻回答出来了。你需要在头脑中一首诗一首诗地回忆,并判断每一首诗的内容是否同时包含了“极”字和“客”字。很显然,第二个问题的难度比第一个问题大得多。
那从程序设计的角度来看,这两个问题对应的检索过程又有什么不同呢?今天,我们就一起来聊一聊,两个非常常见又非常重要的检索技术:正排索引和倒排索引。

什么是倒排索引?

我们先来看比较简单的那个问题:给出一首诗的题目,马上背出内容。这其实就是一个典型的键值查询场景。针对这个场景,我们可以给每首诗一个唯一的编号作为 ID,然后使用哈希表将诗的 ID 作为键(Key),把诗的内容作为键对应的值(Value)。这样,我们就能在 O(1) 的时间代价内,完成对指定 key 的检索。这样一个以对象的唯一 ID 为 key 的哈希索引结构,叫作正排索引(Forward Index)。
哈希表存储所有诗
一般来说,我们会遍历哈希表,遍历的时间代价是 O(n)。在遍历过程中,对于遇到的每一个元素也就是每一首诗,我们需要遍历这首诗中的每一个字符,才能判断是否包含“极”字和“客”字。假设每首诗的平均长度是 k,那遍历一首诗的时间代价就是 O(k)。从这个分析中我们可以发现,这个检索过程全部都是遍历,因此时间代价非常高。对此,有什么优化方法吗?
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

倒排索引技术在海量数据查询中的应用 倒排索引技术是一种重要的检索技术,本文深入浅出地介绍了其原理及应用。通过倒排索引,我们可以在海量数据中快速查询出含有指定关键字的文档。文章详细介绍了倒排索引的创建过程,包括文档编号、关键字解析和插入哈希表等步骤。同时,还讨论了如何通过有序链表归并来快速检索出公共元素,以及多路归并的方法用于对多个关键字进行联合查询。倒排索引的核心实现是哈希表,通过将内容或属性作为key来存储对应的文档列表,实现了在O(1)的时间代价内完成查询。倒排索引技术在数据库的全文索引功能、搜索引擎的索引、广告引擎和推荐引擎等领域都得到了广泛应用。读者可以通过本文快速了解倒排索引技术的原理及应用,为进一步深入学习打下扎实的基础。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《检索技术核心 20 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(29)

  • 最新
  • 精选
  • 无形
    根据作者查询可以给每首诗打一个作者的标签,再把标签作为关键字,标签对应的文档集合即为这位诗人写的诗的集合,如这种格式 key=array "作者_李白"=["将进酒","凤求凰","静夜思"] 这里加的前缀"作者_"可以避免有的诗里面有"李白"这两个字,造成检索结果不准确,实际中key可能把key映射成ID,集合里保存的也是诗的ID,这是一种主动打标签的方式,如果还需要按照朝代查询,再打朝代的标签 对于检索效率的问题,当数据量很大的时候,显然不可能用链表,查询效率太低了,位图相比查询效率就非常高了,每个byte就能表示一个诗的ID,1表示有,0表示没有,因此非常省内存,而且位运算取交集、差集效率非常高,不过普通位图有一个缺点,如果数据稀疏的话比较浪费空间,因此有人研究出了压缩位图,压缩位图的主要思想是把一个int划分为高16位低16位,高16位对应int存储的容器,把低6位放到对应的容器中,容器有三种,有序集合、位图、还有一种忘了名字,会随着数据量的变化选择合适的容器来存储数据,比较节省内存,倒排索引+压缩位图是一个非常强的组合,搜索性能非常高,合适的场景下甚至可以替换ES,提升几十倍搜索性能。快手、华为千亿级用户标签检索系统中也有类似的应用

    作者回复: 非常棒!用不同的key进行区分的确是一个方案。另一个方案是可以在posting list中加域,标明是作者还是内容。 还有,倒排索引的检索效率优化是一个很重要的问题。你说的压缩位图是roaring bitmap,这的确是最近几年很火的一个应用。剧透一下,加餐会讲到。

    2020-04-01
    3
    36
  • 明翼
    老师对于邮件中敏感词检测适不适合用倒排索引那,用的话可能每个邮件都只要检测一次,不用直接搜索可能又找不到近义词

    作者回复: 就像你说的,邮件只需要检测一次,因此对邮件做倒排索引并不适用。而且倒排索引也解决不了近义词问题。 邮件敏感词检测一般是这样的思路: 1.准备一个敏感词字典。 2.遍历邮件,提取关键词,去敏感词字典中查找,找到了就说明邮件有敏感词。 这里的核心问题是如何提取关键词和如何在敏感词字典中查询。 一种方式是用哈希表存敏感词字典,然后用分词工具从邮件中提取关键字,然后去字典中查。 另一种方式是trie树来实现敏感词字典,然后逐字扫描邮件,用当前字符在trie树中查找。 不过,这两种方式都无法解决近义词,或者各种刻意替换字符的场景。要想解决这种问题,要么提供近义词字典,要么得使用大量数据进行训练和学习,用机器学习进行打分,将可疑的高分词找出来。 其实这种近义词处理方案,和搜索引擎解决近义词和查询纠错的过程很像。我在搜索引擎那篇里面会介绍。

    2020-04-01
    3
    10
  • 阿斯蒂芬
    想起了之前看《改变未来的九大算法》(书名比较夸张,但书是好书啊各位),开篇讲到了搜索引擎的「把戏」,就是从单词分词构建单词到网页的链接集合,来实现最「粗糙」的互联网检索冲浪。随后再考虑同时检索到多个满足条件的结果时,如何确定哪一个才更接近我们所需要的。于是在单纯记录单词出现的网页的基础上,加上了单词在这个网页的位置,理论上可以简单认为位置越近,就越符合我们检索条件的输入。 以上两个知识点其实跟老师讲的倒排索引思路类似。思考题的李白,其实也算是一种:假设作者和内容都命中,我们如何能区分哪个才是更接近我们想要的答案。解决这类问题的思路也是相似的,像单词增多一个在网页出现的位置记录一样,也可以考虑让“李白”多增加一个信息,来让计算机知道它是「出现在什么位置」的,当然这里的位置可能就变成了:内容、作者这样的标签或者类型。 人类想借助计算机快算处理结构化数据的特点,将人类知识从小条目到全文的检索关系结构化存储到计算机,实现了「正向索引」,但是贪婪的人类并不满足,调皮大脑还有一个特性就是,全文记不住,全文的这一小段那一小段倒是可能记得溜,所以人类又聪明地让计算机以类似的存储结构但是不同的关系方向来实现全文内容到全文方向的查找,于是出来了「倒排索引」。这个角度来看,说检索技术真是是被人类特征的需求来驱动进展的不为过。

    作者回复: 工业社会的一个特点就是追求效率,如何能更快地完成事情是我们一直在追求的一个目标。检索技术可以说是我们在信息时代的加速器,它能帮助我们更快地获取信息,以及让系统更高速地运作。我相信它会持续地演化和影响我们的未来。

    2020-04-17
    2
    9
  • yang
    加餐是6号出的,倒排是1号出的,所以我先把1号的补完哈~ 你可以再思考一些细节:如果有一些诗的内容里也有“李白”这个关键词,比如杜甫的诗。 那么作者“李白”对应的posting list,和内容中的“李白”对应的posting list是否会冲突?可以怎么处理? key_李白 = posting list; 内容中的关键字作为倒排索引 author_李白 = posting list; 作者的名字作为倒排索引 为避免 关键字 或 名字 或 朝代 相同时,查询出错,通过给索引加 前缀 或 后缀的形式 来区分内容相同类型不同的索引。 老师说的给posting list分域有点想不明白? 看到老师提到进阶会有:压缩位图、磁盘存储、分布式存储。期待老师的进阶篇文章! ps: 终于补到6号的了,马上可以去享受加餐课了! (✪▽✪)

    作者回复: posting list分域,就是一个元素里加上域标识。举个例子,一篇文章有标题,作者,内容三个域,而“李白”这两个字,可能出现在这三个位置。因此,key和posting list可以这么写: key =“李白” -> [id1,标题域:0,作者域:1,内容域:0],[id2,标题域:1,作者域:0,内容域:1]

    2020-04-10
    8
  • 大头爸爸
    是不是倒排索引主要应用在搜索引擎这一块?跟数据库SQL/NOSQL关系不大? 另外,还有一个概念是列式存储,那个是不是主要用在NOSQL,跟搜索引擎关系不大?

    作者回复: 这样下定论会有一点过于绝对。 实际上,倒排索引是一种“根据属性/关键词来查询文章”的技术,只要有这个需要的场景都可以使用倒排索引。搜索引擎只是正好可以大规模使用这个技术的一个应用场景,但这并不意味着MySQL或者nosql不能使用倒排索引技术。实际上在MySQL中就是支持倒排索引的。并且,即使在搜索引擎中,微软的bing也开源了他们的向量检索技术,是基于树的检索技术,而不是倒排索引。 另一方面,列存储更多是一种减少磁盘io和节省存储空间的存储技术(而不是检索技术)。它也没有被明确限定只能在nosql中使用,实际上,关系型数据库也可以使用列存储。至于搜索引擎,它其实是更高层的一个业务应用,它会依赖一定的底层存储,比如说网页存取,索引存取等。这里面其实是可以用到nosql的存储技术的,也就是可以使用列存储的。

    2020-06-14
    7
  • fengyi
    有个问题想请教。如果要搜寻‘极客’这个单词的话。有方法可以重复利用‘极’和‘客’的索引吗。还是要对‘极客’单独作索引

    作者回复: 将“极客”作为一个单独的key进行索引是比较高效的。因为它只在检索时只需要直接将posting list取出即可。 当然,在分词不work的情况下,我们也可以单独对“极”和“客”进行检索,然后在对两个posting list归并时,判断这两个字的位置是否紧邻(在posting list中的每个元素,可以用pos数组记录key出现的所有位置),这样就能判断是否存在“极客”的组合了。这就是搜索引擎会使用的短语查询的方案。你会发现,这种方法会相对耗时一些。

    2020-04-12
    7
  • Bachue Zhou
    “那么问题来了,我们该如何在 A 和 B 这两个链表中查找出公共元素呢?如果 A 和 B 都是无序链表,那我们只能将 A 链表和 B 链表中的每个元素分别比对一次,这个时间代价是 O(m*n)。”不需要这么麻烦,对A建立Hash表,对B搜索Hash表即可,时间代价是O(m+n)

    作者回复: 说得很好,这是更高效的检索方法,在后面加餐篇里我们就会提到这种哈希表法。 在这篇文章中,我想表述的意思是不借助其他的数据结构,单凭原始的链表本身,有序链表会比无序链表更便于查找。

    2020-12-18
    5
  • 李恒达
    老师,我有个疑问,为了实现根据关键词获取数据的功能,是不是需要在正常的表存储的基础上,再额外维护这样一个倒排索引?那这种在关键词不明确的情况下是不是就不会有这个东西了?

    作者回复: 你的思考很好!的确是这样的。你可以回到开头背唐诗的场景。如果只要求给题目背内容,那么是只需要正排索引就好。不需要倒排索引。 倒排索引是用在需要根据部分信息或者属性去反查出数据主体的场景中。搜索引擎就是典型的应用场景,因为我们只知道我们想找什么关键字,而不知道哪些网页有这些关键字,因此需要倒排索引。数据库也一样,很多时候,我们去数据库中查找,也不是直接找id,而是用where去限定一些属性和字段。因此,你会发现,根据我们关心的属性去寻找主体,这种需求其实很常见,这些场景就可以用倒排索引了。

    2020-04-01
    5
  • 范闲
    拉链的是倒排索引在数据量不大的情况下应该很好?如果数量上去了,要改成跳表了吧?如果跳表也支撑不下去了呢?

    作者回复: 你的问题我理解有两点: 1.检索效率问题。 2.存储空间问题。 关于检索效率问题,马上会出来两篇热腾腾的加餐,和你聊聊怎么进行倒排索引的检索加速。 关于存储空间问题,我接下来在进阶篇会开始介绍解决方案。

    2020-04-01
    5
    4
  • 时隐时现
    每个留言问的到位,作者回复的也耐心,支持

    作者回复: 讨论区其实是一个思维碰撞的地方。毕竟文章篇幅有限,不可能事无巨细都说一遍。 因此,如果有什么不清楚的,或者想延展讨论的,都可以在这里交流,相信通过这样的交流,能让更多的人更深入地理解这些知识点。

    2020-05-05
    3
收起评论
显示
设置
留言
29
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部