X

ElasticSearch分片内部原理

以下内容需要具备搜索引擎和elastic search的基础知识,了解什么是倒排索引,什么是es的数据节点,es的分片和写入过程等。

ES的refresh_interval有什么用

一,首先要知道倒排索引是不可变的。这样设计的好处,是避免大量写入的锁冲突,以及磁盘的随机读取和文件缓存系统的缓存。

这样就带来了一个问题,倒排索引不能改变,那么CRUD写怎么办呢? es的做法是每一秒(refresh_interval参数设置)生成一个新的段,接受不断的追加写入。同时,更新不是真正的更新,而是把旧的数据标记为删除,新的数据追加到后面。es有一个.del文件,记录的是删除的文档,在搜索结果出去的时候,会用这个文件进行过滤,避免把删除的搜索结果展示出来。

而这个refresh_interval控制的就是,新段被创建的频率。一个新的段被创建,需要被打开,才能被搜索到。按照传统的做法,一个新的段,被写入磁盘之后,再打开,才能被搜索。而fsync刷盘不能频繁的进行,他是一个漫长的过程,所以这里就需要解决这问题。es的做法是,一个新的段被创建,是创建在缓存里,新段创建的时候,旧段就可以在缓存中被打开了,也就可以被搜索到了。

这样做虽然加速了搜索可见的速度,但是带来了持久化的问题。如果这个时候,机器掉电/宕机,这部分数据就全部丢失了。为了解决这个问题,es引入了translog,只有写入了translog写入了文件之后,这一次的写入请求才算成功。

最后,当translog很大的时候,一次性的将这些事务的日志异步的刷入磁盘,并且清空translog进入到下一个循环。一个es的数据节点,在启动的时候,需要读取tranlog去做数据恢复。

而以上所有的过程,都是可以通过参数配置,来改变这些行为的。

es段合并是什么

如上所述,es通过不断的创建新的段,来解决倒排索引不可改变的事实。大量的段必然带来文件句柄的开销,以及查询的效率。每一次搜索行为,都会搜索所有的打开的段文件。
段合并,就是一个文件整理的过程,将很多碎小的段,合并成一个大的,同时把已删除的文档,从倒排索引中移除。

doc_values:配置是做什么的

我们的普通搜索查询,是利用倒排索引,通过一个词条,获取命中了这个词条的文档。由于倒排索引的数据结构,让我们很容易的做到。

词条 文档
连衣裙 doc_1,doc_2,doc_3
T恤 doc_2,doc_4
白色 doc_1,doc_3,doc_5
黑色 doc_1,doc_4,doc_6

而另外一种场景呢,比如我想知道查询连衣裙里什么颜色的最多?你需要知道doc_1,doc_2,doc_3一共包含有多少颜色,然后统计,那个颜色最多。通过doc_id来反查,这个文档下有多少词条却不是件容易的事情。因此有了doc_value,他是下面一种数据结构,和倒排索引是反的。

文档id 词条
doc_1 连衣裙,白色,黑色
doc_2 连衣裙,T恤

这个结构,在我们聚合查询和排序的时候,都会用上(排序要算分,算分的时候,需要统计词频)。

默认情况下,doc_value会在所有字段上打开(text:analyzed除外),他在创建索引的时候,同时创建的。如果你的字段不参与聚合和排序,完全可以关闭。

Fielddata:doc_values的补充方案

那如果我要到text:analyzed的字段上进行排序,或者聚合怎么办呢? es提供了一个fielddata的选项(默认在text:analyzed字段上开启)。和doc_values不同的是fielddata使用的是JVM的堆内存(doc_values使用的是堆外内存),而且是常驻内存。所以如果不加控制很容易导致Java的OOM,因此es有个断路器的设置,计算这次会超出阈值的时候就会发生熔断,抛出类似 [fielddata] Data too large, data for [_id] would be [7267783454/6.7gb], which is larger than the limit of [6871947673/6.3gb] 的错误。

还有个场景,就是你使用_id进行排序的时候,也会使用fielddata,这个也会导致上面的错误。所以一个同学的查询case里,使用了_id进行排序,导致了上面的报错。

norms:false

在索引被写入的时候,如果这个字段要参与算分(tf/idf或者是bm25),都会用到这个文档里,这个词出现了多少次,以及这个文档的长度是多少。如果每次搜索都要算这么一遍,显然是不划算的。因此,在es的index的时候,就会提前把这些值存储下来,用来算分。如果你的字段不需要参与算分,也可以显式的配置norms:false来把这个字段的这个存储关闭掉,以节省空间减速index的过程

index:fase

这个选项是关闭了这个字段的索引过程,很多时候我们的字段并不需要构建索引,仅仅是查询到之后,想要查出这个document的附加信息,这个时候可以把这个字段关闭掉,以节省空间

Categories: ElasticSearch
龙安_任天兵: 不忘初心,方得始终!