ElasticSearch索引机制以及Segment解析

ES采用的索引是什么?

ElasticSearch采用的是Lucene的倒排索引技术,即以分词的形式将文档分解成单词+频率+位置的形式

倒排索引以及优点

倒排索引的含义:
一种索引方法,被用来存储在全文搜索下某个单词在某一个文档或者一组文档中的存储位置的映射。也可以称他为反向索引。
备注:
我们一般数据库都拿一个自增的id作为主键,也就是索引,ES就是走独特,将映射作为索引。
举个例子:
在这里插入图片描述
在这里插入图片描述
可以看出来:

  • ES为每一个字段都建立了一个倒排索引,而每个字段下的值叫做Term。
  • Posting List:一个int类型的数组,存储了所有符合某一个Term的文档的Id,也可以理解为位置集合

基本上会有三种文件去存储某一条数据:

  1. Term Dictionary 词典文件,存储一些分词的前缀
  2. frequencies 词频文件,存储这个分词出现的频率
  3. positions 位置文件,存储这个分词出现的位置

ES索引的优点:

  1. 写入磁盘的倒排索引是不变的。
  2. 也因此,不需要添加锁。
  3. 增强读性能。
  4. 提升其他的缓存性能。新增的数据存储在Segment,Segment又存储在文件系统的缓存当中

Term Dictionary和Term Index

Term Dictionary:
ES为了快速定位到某一个Term,会将所有的Term进行一个排序,需要查询的时候,用二分法的方式去查找。形如字典里先查偏旁
Term Index:
ES采用与B-Tree一样的想法,用内存去查找Term(快),而不是磁盘。Term Index像一棵树,包含了Term所在的地址。
形象的说,查询从Term Dictionary中查找偏旁,查到对应的偏旁后,可以看到这个偏旁下,有哪些字,分别在哪一页,这就是Term Index。
在这里插入图片描述
因此这里说明一个很重要的点,就是Term Index不是存储所有的Term,而是存储一个Term Dictionary的一个映射关系。比如以字母A开头的存在哪些分词,在哪些位置,而Index存储的就是这些位置。

ES的索引压缩

ES对索引的压缩

ES的索引是存储在内存当中的,也因此查询的速度非常的快,但是内存的大小是有限的,也因此ES会对他的索引进行压缩。
一般查询是从Index中查找到DIctionary中对应的block,再去磁盘中去查找,而不是直接去磁盘当中去随机的查询,这样有个好处就是:减少磁盘的随机IO次数,增加效率。
言归正传,ES采用FST的形式去把索引进行压缩的。
简而言之就是,FST以字节的形式去存储所有的Term Index,用字节存储的话,肯定是占用空间很小的。因此能够有效的缩减存储所需的空间。
另外FST还有另外一个作用:快速确定某一个Term是否存在系统当中。

ES对Posting List的压缩

举个例子:我们人,对于性别,只有男和女(不男不女的就pass,也不存在),如果一个Type下,有多条数据(Document),加入有一百万条,然后又以性别作为索引,那么想一想,这个Posting List是不是也有最短的是不是也有五十万条。这个数据量有点大。
因此,ES使用增量压缩编码,也就是大数变小数,然后按照字节存储。这种存储方式叫做Roaring BitMaps(RBM压缩)
放图:
在这里插入图片描述

ES索引小总结以及使用时注意的地方

ES的索引思路总的来说为2点:

  1. 尽量把数据写到内存当中,减少磁盘的IO开销,增加查询的效率
  2. 利用多种压缩算法,压缩数据。FST压缩索引啊,RBM压缩Posting List啊等等

ES的索引在使用的时候应该注意哪些地方:

  1. 因为索引是默认建立的,因此不需要使用索引的地方,一定要在定义的时候就声明出来。
  2. 对于String类型的字段,在ES中分为text类型和keyword类型,不需要analysis的地方也要明确的声明出来。
  3. 选择有规律的Id进行创建,否则默认创建的是随机的,没有规律的ID,这样今后进行数据压缩的时候,不方便,压缩的性价比低。

Segment分段是什么

就是将一个大的索引拆分成多个小段,即Segment,而每一个Segment本质上就是一个倒排索引。

Segment不可更改,那么ES数据如何更新?

首先,在Lecene中,在创建索引的同时,会维护一个commit point的文件,这个文件的作用是什么?

  • 记录当前所有可用的Segment

什么叫做可用的Segment,就是可以拿来查询数据的Segment,因为一条数据,也就是一条Document,是存放在Segment当中的,因此在commit point中搜索数据的时候,相当于在它里面的各个Segment中去查找,最终的结果由每个Segment的返回结果汇总而得到。

ES的写入流程

先放图:
在这里插入图片描述
流程:

  1. 首先有一条新数据要加入,则这个文档会先放到内存缓存中。

  2. 当这个缓存中的文档数量到达一定程度/一定的时间点的时候会做一个操作:对缓存进行commit,具体又分以下几种步骤:

    1. 将当前缓存中的所有文档形成一个新的Segment(相当于一个容器),并写入磁盘。
    2. 生成一个新的commit point,用来记录当前可用的Segment。
    3. 等待所有的数据全部写入磁盘,
  3. 打开新增的Segment(打开后,才可以对当中的内容进行搜索)。

  4. 清空缓存,准备新的数据写入。

  5. 重复以上操作

问题来了,前面说过Segment不可以改变,那么ES如何对数据进行删改?

答案:
每一个commit point实际上还维护了一个叫 .del的文件,它用于记录某一个Segment下的某一条文档已经被删除(其实这个删除并不是真正意义上的删除,而是对要删除的数据进行一次标记)。

  • 删除一条数据后查询:比如我们要查询一条已经删除的数据,但是在查询的时候,其实这条数据依旧能够被查询出来,但是再返回结果的时候,ES会根据.del文件中的记录,把有记录过的文档进行过滤,因此只是返回结果我们看不到了而已,实际上被删除的数据还在。
  • 修改一条数据后查询:这条被修改过的文档,同样还存在,只是ES会声明该文档被删除,而是创建一条新的文档,存入新的Segment。同样是返回结果的时候被过滤掉。

refresh是什么

refresh指的是将缓存中的文档写入Segment,并打开Segment,让他可以被搜索的过程。
Document在写入Segment后,Segment会先把数据写到文件系统中的缓存当中,之后再逐渐的flush到磁盘当中。
备注:

  1. 在缓存当中的Segment同样可以被读取,哪怕没有写到磁盘
  2. 默认情况下,ES refresh的频率为1s,因此你新加了一条数据,在下一秒就可以被搜索,也因此ES被称为可以实时的搜索。

下图指的是,buffer中的数据封装到一个集合Segment中,然后这个Segment放到文件系统的缓存中,也就是下图红框圈起来的部分。
在这里插入图片描述

Flush和translog的含义

Flush:将缓存中的Segment全部写入到磁盘当中,并且确定写入是成功的。
translog:为了防止缓存中的Segment还没有来得及被commit到磁盘当中,就发生了一些意外,比如断电等情况,而导致数据丢失。因此ES引入了translog文件来保存这些记录。

流程图:

  1. List item
  2. 在这里插入图片描述
  3. 在这里插入图片描述

最后说明以下Segment还有合并的机制。其实很像Redis中的日志进行压缩。
这里再把ES中对数据的删除拿来提一提。
ES因为会定期的把一些小的Segment或者没用的Segment进行合并(减少存储占用空间),如果存在于.del文件中的记录被合并了,此时ES会把存在于.del中的对应记录给删除。这个时候才是真正意义上的把这个数据删除了

感谢阅读。

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值