倒排索引、正排索引,以及ElasticSearch对倒排索引的优化方法
正排索引与倒排索引
首先,我们需要这两种索引方式是要干啥?其实任何一种索引模式,都对应的是不同的信息存储方式。这样不同的存储方式,主要是为了不同的查询要求而定的。正排索引和倒排索引就是如此,正排易维护,但搜索代价很大(耗时间);倒排搜索快,但建立倒排索引时间久、文档库的每次更新都意味着倒排索引的重建,故维护较麻烦。但由于倒排索引的建立可以放在线下,所以这一般来说不是太大的问题。
正排索引
正排索引就是最普通的索引排序方式。正排索引也是采取key-value pair的方式对数据进行保存,key是doc-id,value则可以存储多种内容,如doc的分词词表、doc所在网页的属性信息等。由此可见,正排索引可以随意添加数据,但如果你要查询某个单词在哪些文档中出现,那么你就不得不将全部文档都遍历一遍,若文档库极大,则时间消耗是不可接受的。
倒排索引
倒排索引是Lucene和ElasticSearch用来做全文检索的标配。倒排索引类似将正排索引反过来,以全部文档中出现的所有words建立一个term dictionary
,然后对于term dictionary
中的每个词,它后面都会跟随一个链表,该链表就是 倒排表
,倒排表
内存储着如下信息:
- 该词出现的doc-id
- 该词在某doc中的出现次数和出现位置
如此一来,倒排索引就可以在用户输入查询query时,将query分词成一个个token,然后将一个个token带到term dictionary
去“查字典”,然后获得出现该词的doc-id集合,最终在这若干个token对应的若干doc-id集合上做交集,得到最符合用户query查询的结果。
由此可见,倒排索引大大加快了查询速度,然而一旦有新的文档加入文档库,你就要重新做一次"入库操作",即建立倒排索引的操作。因为此时各个token在不同文档中的出现次数、以及每个token对应的 倒排表 都可能发生变化。
倒排索引的进阶——倒排索引如何进一步加速?
从上面的介绍可知,倒排索引的建立这么麻烦,其主要目的就是加速。所以除了索引建立策略上,我们在数据结构和查找策略方面也要最大程度节省时间。那么倒排索引还做了哪些速度性能优化呢?
在 term dictionary
基础上再建 term index
从左到右,分别是term-index、term-dictionary、posting list(倒排表)
我们可以将整个ElasticSearch的查找过程当做“查字典”过程。对于大型ES库而言,当你的文档数目很多的时候,你的目录必然也会很长(毕竟字典里的term变多了嘛)。所以,此时你就只能将term dictionary
放在磁盘上。即便我们对term dictionary
中term的顺序进行有规则排序,从而在查询时可以执行 二分查找
,我们也还是会在搜索时多次访问磁盘,从而因磁盘IO限制降低了查询速度。
为了解决这个问题,ES/Lucene引入了 term index
,其本质就是个字典树。至于字典树是个啥(https://zh.wikipedia.org/wiki/Trie)。字典树记录了term的前缀信息,例如以下words组成的字典:
sand, sad, say, said, seed, search, sorry, sore, shabby, sherry, shadowsock, score, scholar…
我们可以建立字典树,分别记录由前缀 sa
、 se
、so
、 sh
、sc
组成的词在 term dictionary
中开始的位置,从而一下子大幅降低我们查词典时的搜索空间、减少访问磁盘的次数(其实新华字典不也是这么干的么~)。与此同时,我们还可以将字典树term index 存在内存上。所以说,ElasticSearch的优化,有时候就是字典树term index
占内存大小和搜索速度这两方面的权衡——字典树越大,你可以定位到的前缀信息越多(比如从只定位 sa
-> sad
、san
、 sai
…),你在磁盘的term dictionary
中做二分查找的次数肯定也会更少,速度就越快;但内存空间是有限的,你不可能无限扩张你的字典树。
倒排表求交集的加速
设想一个用户输入这样一个query:Boston Celtics Calendar
,即波士顿凯尔特人队赛程表。我们将query分成三个term -> Boston
, Celtics
, Calendar
. 我们对这三个词到倒排索引中进行查询,最终得到三个倒排表。假设倒排表是这样的(极简版,实际上倒排表内容会更多)
Boston -> [12, 13, 24, 28, 40, 42, 46, 51, 56, 59]
Celtics -> [2, 12, 13, 40, 43, 44, 46, 58, 59]
Calendar -> [0, 1, 12, 15, 20, 40, 46, 51, 55, 59, 60, 62, 65]以上交集结果:[12, 40, 46, 59]
首先,对于此类有序数组,做交集有个很强大的数据结构——跳表(skip list)。这个数据结构很简单也很精巧,在这儿不再详述。
其次,假设全部文档真的都是这种integer格式的id,那么对内存的考验极大。一个int类型至少需要2 byte,50M个doc-id就是100M的内存占用,所以说显然在doc数量较大的情况下integer类型的doc-id有其局限性。
那么如果不用 integer+跳表
的方式来做交集,还可以用啥方法呢?使用Bitmap
的方法:
对于一个doc-id list [1,2,5,7],我们可以转为[1, 1, 0, 0, 1, 0, 1, 0],另一个list[1,2,8] -> [1, 1, 0, 0, 0, 0, 0, 1],显而易见,这其实就是做了个类似“one-hot”的操作,将doc-id对应的位置置为0,若存在于倒排表里,就设为1。这样做更节省内存占用,因为每个doc-id是非0即1的,只占1 bit,即1/8 byte. 50M的doc-id,这样只需要 50M*1/8 byte = 6.25M的内存占用,是不是节省了一大笔开销?而且位运算速度可是计算机做的最快的运算方式!
但有个小问题——bitmap
方法对应的每个倒排表实际上内存占用都是一致的,都是长度为全部doc-id这么长的list。在面对doc-id数量较少的求交集运算时,这样做就显得有点冗余。举个例子,假设Boston
, Celtics
, Calendar
分别对应doc-id的集合为[1,2]、[1,3]、[1,4],但doc-id一共有50M篇,那么虽然参与交集运算的每个list最多只有2 * 2 byte = 4 byte,但我还是得对每个倒排表开6.25M的内存空间,这是不是有点杀鸡用牛刀呢?所以,依据doc-id总量的不同,到底是 integer+跳表
还是 bitmap
也是可权衡的。
这就是ElasticSearch/Lucene在交集运算时的优化。
倒排索引、正排索引,以及ElasticSearch对倒排索引的优化方法相关推荐
- 正排索引(forward index)与倒排索引(inverted index)
一.正排索引(前向索引) 正排索引也称为"前向索引".它是创建倒排索引的基础,具有以下字段. (1)LocalId字段(表中简称"Lid"):表示一个文档的局部 ...
- 正排索引和倒排索引的区别
1.正排索引 蜘蛛爬虫经过文字提取.中文分词.去重等操作后,得到的就是独特的.能反应页面的主题内容.以词为单位的字符串.接下来搜索引擎索引程序就可以提取关键词了,为该页面建立与关键词的对应关系,而这个 ...
- mysql是正排还是倒排_正排索引和倒排索引的区别
建立索引是搜索引擎对网站页面的tag title.meta descripiton.描述.抓取记录.页面外链等等,进行标记添加的行为.这其中,还将对页面中的关键词信息进行识别和储存,当用户搜索的时候, ...
- 白话Elasticsearch50-深入聚合数据分析之基于doc values正排索引的聚合内部原理
文章目录 概述 思考 知识点 举例说明 纯用倒排索引来实现的弊端 倒排索引+正排索引(doc value)的原理和优势 概述 继续跟中华石杉老师学习ES,第50篇 课程地址: https://www. ...
- 搜索 正排索引 和 倒排索引 区别
一.什么是正排索引(forward index)? 简言之,由key查询实体的过程,使用正排索引. 例如,用户表: t_user(uid, name, passwd, age, sex) 由uid查询 ...
- 倒排索引、正排索引系列一
1. 搜索引擎简介 搜索引擎顾名思义就是:从千万设置亿.兆级别的数据中查询出自己想要的信息,比如:谷歌和百度 索引引擎最重要的是建立倒排索引和正排索引[不是必须的] 2. 倒排索引简介 倒排索引的名词 ...
- 倒排索引 java_es倒排索引和正排索引(示例代码)
搜索的时候,要依靠倒排索引:排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values. 在建立索引的时候,一方面会建立倒排索引 ...
- music算法_Elasticsearch系列---相关性评分算法及正排索引
概要 上一篇中多次提到了按相关性评分,本篇我们就来简单了解一下相关性评分的算法,以及正排索引排序的优势. 评分算法 Elasticsearch进行全文搜索时,Boolean Model是匹配的基础,先 ...
- 用 Golang 写一个搜索引擎(0x07)--- 正排索引
最近各种技术盛会太多,朋友圈各种刷屏,有厂商发的各种广告,有讲师发的各种自拍,各种参会的朋友们各种自拍,好不热闹,不知道你的朋友圈是不是也是这样啊,去年还没这么多技术会议,今年感觉爆发了,呵呵,真是一 ...
- 用Golang写一个搜索引擎(0x07)--- 正排索引
最近各种技术盛会太多,朋友圈各种刷屏,有厂商发的各种广告,有讲师发的各种自拍,各种参会的朋友们各种自拍,好不热闹,不知道你的朋友圈是不是也是这样啊,去年还没这么多技术会议,今年感觉爆发了,呵呵,真是一 ...
最新文章
- locate 命令详解
- HugeGraph Server/Hubble安装使用
- 北交大计算机学院复试经验,2014考研复试:过来人考研复试经验谈-北交大计算机系...
- leetcode - 1143. 最长公共子序列
- 华为nova 4e预热海报曝光:3月14日正式发布!
- 基于Linux和MiniGUI的嵌入式系统软件开发指南(六)
- 阿铭Linux_网站维护学习笔记20190305
- 电路串联和并联图解_初三物理串联和并联电路知识大全
- 网络安全----身份认证
- java读取加密excel_Java 加密和解密Excel文档
- TypeWriter: Neural Type Prediction with Search-based Validation基于搜索的神经网络预测器
- UITableViewCell设置行距
- 【转】贾佳亚港中文团队冠军技术分享:最有效的COCO物体分割算法
- 广电电视信号如何生成RTMP流进入流媒体系统网络分发实现手机APP播放
- html如何让窗口不在任务栏显示,电脑最小化窗口后无法在任务栏中显示怎么解决...
- WPARAM与LPARAM 之区别
- php链接数据库2000,在Win2000下用PHP和JSP连接MySQL
- Oracle RAC 19C通过故障组更改OCR和voting磁盘
- 美国普渡大学 计算机科学,普渡大学西拉法叶分校计算机科学系怎么样?
- 第十篇 Spring AOP中Load Time Weaver
热门文章
- CPU-Z V1.99 x64 得分
- rockchip RGMII+mv88e6390 管理型交换机功能调试及vlan定制+Mac绑定
- 小鸟云服务器:网络基本概念服务、协议、进程、端口之间的关系
- 中国最大的IDC世纪互联是如何成为云计算时代的看客的
- 苹果手机怎么设置专属铃声?看一遍就能学会的超简单教程
- Elasticsearch Sliced Scroll分页检索案例分享
- 信息内容安全-《人民的名义》人物图谱分析实验
- 传递给Appium服务器以开启相应安卓Automation会话的Capabilities的几点说明
- Julia之初体验(九)字符串连接与匹配
- 同济大学Python程序设计基础 实验七:文件