不愧是我,一晚上教会了女神倒排索引

你将花费10分钟读完本篇文章,读完本文你将:

  • 熟悉索引再Elasticsearch的作用
  • 熟悉正排索引和倒排索引的原理区别
  • 掌握索引的压缩算法原理

引言

这是一个安静的晚上,我在峡谷里打团,突然微信弹出一串消息,我一看,原来是女神又找我聊天。

女神:在么?

我:在在在,怎么了?男朋友又惹你生气了吗?

女神:没呢,我现在是两耳不闻窗外事,一心只学Elasticsearch😊

我:说吧,这次又是什么问题?

女神:听了上次学长的介绍,还是没有搞懂为什么Elasticsearch的搜索会更快呢?比如我在一篇文章里面进行查找,那我还是需要对文章全文检索啊?

我:很棒的问题,已经会全文检索这个词了。是的Elasticsearch或者说任何一个查找在最坏的情况下都需要对文章进行全部的检索,Elasticsearch快速的原因之一,是他采用了倒排索引的数据结构。

正排索引

我:首先,我想跟你强调一下索引的概念。索引相当于图书的目录,可以在目录中找到对应的页码,快速定位到对应的数据,这时候有两种思考的方向。

女神:我知道,我知道,肯定有一种,就像我说的这种查找方式,把文章都摆在那,然后一个一个去匹配。

我:是的。你的这种查找的方式符合正排索引forward index的概念。一般我们会给文章一个标识,再对文章进行分析,比如文章有哪些词语啊,这些词语出现了多少次,这篇文章在什么文件中的位置,这样更方便我们去查找。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1bxhHf94-1648776230851)(/Users/huxingbo/Documents/elastic/正排索引.png)]

女神:这样啊,那我们怎么去查找一篇包含某个词语的文章呢?

我:就像这样的结构,当我们需要查找某个信息的时候,我们可以去文档的列表里面遍历查找。首先需要找到文档(1),之后对文档下存储的词语进行遍历匹配,提取出需要的信息,再到下一个文档,重复查找操作。

女神:这不是傻子查找嘛,果然是我想到的方式😭

我:正排索引虽然在查找检索上很傻,但是它在别的地方表现却很好哦,这个地方我先卖个关子,我跟你说一下第二种思路吧。

倒排索引

举个栗子

假设八佾有个朋友,但这个朋友,不是八佾本人。在农历新年给领导写信,但是有两个领导是八佾的朋友很想骂sillybee的,于是他大胆的在信中这么写。

doc1:"dear leader ,you sillybee"

doc2:"dear leader ,i have to thank a happy silybe new year "

doc3:"dear leader ,i have to say happy new year"

三封已经封好的信, 八佾的朋友是个聪明的IT从业工作者(但他远没你想的那么聪明),担心自己分不清三封信,于是 他记录下了这么一张表。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdFssTtq-1648776230853)(/Users/huxingbo/Documents/elastic/倒排索引表.png)]

我想帮他向你们解释一下这张表,第一列是出现的单词,第二列是单词出现的文档位置。例如,dear这个单词出现在文档1,文档2和文档3。sillybee这个单词出现在文档1中,这样就能快速找到文档出现的位置了。

下个定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wK02fHlQ-1648776230853)(/Users/huxingbo/Documents/elastic/倒排索引原理图.png)]

我:所以倒排索引的数据结构相比于正排索引就变成了这个样子。从词语去查找文档出现的位置,这样是不是更加快捷,就像八佾的朋友一样,立即就能找到关键词的文档在什么位置。

女神:你的这个朋友可真厉害!果然技术改变命运。后来呢,他又出任CEO,当上总经理吗?

我:他可没有你想的那么厉害。在贤者时间的时候冷静下来,毕竟还要为五斗米折腰,骂人的信不能寄出去,想要剔除出来,于是自信的通过上面的表,找到了sillybee这个词项,找到了对应的记录,第一 封信中有,于是快速的找到了骂人的信,后来他兴高采烈的把信寄了出去。

我:但是粗心的他把sillybe,写成了silybee,但是领导可不会get不到这个单词是骂人的意思。看来朋友并没有用好这 个倒排索引表。

女神:啊~那他好惨,要是他能进行一些词语的处理,如果查找sillybe的时候也查下silybee或者sillyb,就能发现了。

我:是的,所以Elasticsearch想到了这里,提供了丰富的文档处理。比Analyzer分词器,会对文本中的词按一定规则进行切分。因为不同的语言分词的规则不一样,比如中文和英文就有着不同的切分规则,还有一些模糊匹配,停用词等的,这个后面有机会我们再详细的探究。

正排索引和倒排索引的应用场景

女神:既然倒排索引的检索性能这么高效,为什么还需要正排索引呢?

我:你还真是抓住这个问题不放呢?你试想一下这样一个场景,你现在想去博客里面搜一篇Elasticsearch Index Module的文章,那么你想在你的页面上出现的博客排序是什么样的呢?

女神:当然是相关度越高越好啦,要是我找我就给他们每个文档打个分。

我:是的呢,Elasticsearch也是这么做的,只是对于相关度的定义的评分有着复杂的公式,从词频,逆向文档频率等各个维度来判断,这时候的倒排索引就很难胜任这样的工作

女神:对对对,因为倒排索引是根据关键词去找文档,然后再对文档分析,这时候文档本身的一些排序因素确实好像不好存,那Elasticsearch是怎么做的呢?

我:Elasticsearch在整个搜索排序的过程中:①倒排索引利用检索的高性能找到关键词能匹配的结果集。②之后由正排索引完成排序、过滤和聚合的功能。

女神:还是Elasticsearch厉害!!!👍🏻

我:说到这里,你了解了倒排索引,就知道为什么这种查询方式会更快了吧,但是你有没有发现这是一种很大的浪费?

女神:啊,对对对,我刚刚就想问,如果我们对文档的关键字都提取出来,记录文档的位置,记录出现的频次,记录各种信息,那我是不是要更大的空间来存储。

我:对的,一些必要的信息,比如说频次,位置啊是必须要存储的,但是我们知道,一个关键词后面有着很多个doc列表,存储着DOC id,这样就有大量的docid重复,这里有一些编码压缩的方法。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3VcBqpe-1648776230853)(/Users/huxingbo/Documents/elastic/倒排索引的id.png)]

倒排索引的压缩算法

FOR

FOR的全称是Frame Of Reference,主要思想是先对DOC ID列表进行排序,之后使用差值的方式进一步压缩,这样需要表示的数字更小,占的位数少,需要空间就更少。这么说可能太抽象了。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JIgHqYlj-1648776230854)(/Users/huxingbo/Documents/elastic/压缩的id实例.png)]

我:第①步:先对doc id的列表进行升序排列,众所周知一个整数在计算机中用4个字节表示,因此6个数占得字节是24个。

我:第②步:对doc id进行向前求差得出delta list,将大数化小

我:第③步:对delta list进行分块,使得更小的数占更小的字节,用一个字节来表示,该块中的每个数占多大的位数,如图左边的绿色表示每个数都是7位,也就是7位一个数。右侧绿色表示的是每个数是5位,这样在反编码的时候,我们可以再恢复到原先的doc id。

女神:这设计的也太巧妙了吧?那Elasticsearch采用的就是这种存储方式么?

我:其实这种方式总结来说就是:拉链归并只是这种编码方式还是有些弊端的。比如说对数据的处理上来说,编码越复杂,追求更高的压缩率,那么对于查询来说效率就会更加低下

RBM

由于拉链归并的思想,Elasticsearch对一些常用的过滤器进行了缓存,用来加速一些过滤器的执行,因此带来了几个问题:

  1. 因为不能缓存所有的过滤器,所以压缩比例对于倒排索引的编码匹配来说不那么重要
  2. 我们需要加速一些重复执行的过滤器,因此一个好的数据结构来说很重要
  3. 过滤器存储在内存中,而正排表基本上是在磁盘上

面对此种情况,Elasticsearch列举了一些对应的方案,进行了均衡。

第一种方式:整型数组

最直接的选择就是数组,因为数据的遍历性,可以极大的提速。然而压缩性却很难保证。如果你需要存储100Mb的文档,那么你就至少需要400Mb的空间。

第二种方式:bitmap

位图是一个数组,其中每个条目只占用一位,因此它们只有两个可能的值:0 或 1。

为了知道 docID 是否包含在位图中,需要读取索引 docID 处的值。 0 表示该集合不包含此 docID,而 1 表示该集合包含此 docID。迭代需要计算连续的零,这实际上非常快,因为 CPU 有专门的指令。如果我们与整型 相比,密集过滤器的内存使用率要好得多,因为我们现在只需要 100M 位 = 12.5MB。

但是这种情况下会有稀疏集的问题:虽然我们的第一个选项每次匹配需要 4 个字节,但现在无论有多少匹配,我们都需要 12.5MB 的内存。

第三种方式: roaring bitmaps

RBM是为了兼顾数组的遍历性和位图的低存储空间。具体的过程是这样的:

我:首先根据docId的高16位进行分块,每个块最多包含65535个,例如第一个块存储的是docId(0-65535),第二个块表示的docId(65536-131071)。这样用来解决bitmap的稀疏集的问题,使得每个块里的docId更加的稠密。这样我们就可以使用 bitmap的特性,但是此时数组的特性如何使用呢?

我:第二步,对docid进行分配,使得数据稠密,范围在集中的块里

我:第三步,上面部分解决了数据稀疏性的问题,但是如何用上数组的易于遍历呢?此时Elasticsearch做了一个实验。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nHijywFu-1648776230855)(/Users/huxingbo/Documents/elastic/4096实验.png)]

我:根据图中可以看到当4096之后的数组内存使用是高于bitmap的,所以如果docId的个数小于4096个的时候就使用数组,如果高于4096个的时候就使用bitma,这样做出了均衡。

女神:哇,简简单单的压缩两个字,里面竟然包含了这么多的知识。了解了这么多,我还是不知道Elasticsearch怎么使用?你应该还不困吧?

我:哈哈哈,你可真是个机灵鬼。明天你把电脑带过来,我们实操一次,把你的电脑打造成Elasticsearch的学习机😎😎😎

女神:嘻嘻嘻😁

八佾Talk

冉求曰:”非不说子之道,力不足也。“

子曰:”力不足者,中道而废。今女画。“

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是 SQL 索引的基础及进阶知识与用法: 一、索引基础知识 1. 索引是什么? 索引是一种数据结构,它可以提高数据库的查询效率。索引包含了表中一列或多列的值,以及指向每个数据行的指针。 2. 为什么需要索引? 当表中的数据量比较大时,没有索引的情况下,查询的效率会非常低。而通过在表上创建索引,可以提高查询效率,缩短查询时间。 3. 索引的类型 常见的索引类型有:B-Tree 索引、哈希索引、全文索引等。其中,B-Tree 索引是最常用的一种索引类型。 二、索引进阶知识 1. 索引的优缺点 优点: - 提高查询效率; - 减少磁盘 I/O 操作。 缺点: - 占用磁盘空间; - 创建和维护索引会增加写操作的开销; - 当数据量变化较大时,需要重新构建索引。 2. 如何选择索引列? - 选择经常用于查询条件的列; - 选择唯一性较高的列; - 选择经常用于排序、分组的列; - 不要选择经常修改的列。 3. 如何创建索引? 可以使用 CREATE INDEX 语句来创建索引。例如:CREATE INDEX idx_name ON table_name (column_name); 4. 如何删除索引? 可以使用 DROP INDEX 语句来删除索引。例如:DROP INDEX idx_name; 5. 如何查看索引? 可以使用 SHOW INDEX 语句来查看表的索引信息。例如:SHOW INDEX FROM table_name; 6. 如何优化索引? - 优化查询语句,避免全表扫描; - 选择合适的索引列; - 避免使用 LIKE 操作符; - 控制索引的数量,避免过多的索引; - 定期维护索引。 总的来说,SQL 索引是提高数据库查询效率的重要手段。掌握索引的基础及进阶知识,可以帮助我们更好地设计和使用数据库索引。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值