Elasticsearch 中数据是如何存储的

使用 Elasticsearch 的时候,我们常常需要关注数据存储在 Elasticsearch 中的存储容量。下面,我们来了解一下 Elasticsearch 中的数据是如何存储。

一、Elasticsearch 索引结构

Elasticsearch 对外提供的是 index 的概念,可以类比为 MySQL DB,用户查询是在 index 上完成的,每个 index 由若干个 shard 组成,以此来达到分布式可扩展的能力。比如下图是一个由 10 个 shard 组成的 index。

shard 是 Elasticsearch 数据存储的最小单位,index 的存储容量为所有 shard 的存储容量之和。Elasticsearch 集群的存储容量则为所有 index 存储容量之和。

一个 shard 就对应了一个 lucene 的 library。对于一个 shard,Elasticsearch 增加了 translog 的功能,类似于 HBase WAL,是数据写入过程中的中间数据,其余的数据都在 lucene 库中管理的。

所以,Elasticsearch 索引使用的存储内容主要取决于 lucene 中的数据存储。

二、lucene 数据存储

下面了解一下 lucene 的基本概念。

1. lucene 基本概念

  • segment : lucene 内部的数据是由一个个 segment 组成的,写入 lucene 的数据并不直接落盘,而是先写在内存中,经过了 refresh 间隔,lucene 才将该时间段写入的全部数据 refresh 成一个 segment,segment 多了之后会进行 merge 成更大的 segment。lucene 查询时会遍历每个 segment 完成。由于 lucene 写入的数据是在内存中完成,所以写入效率非常高。但是也存在丢失数据的风险,所以 Elasticsearch 基于此现象实现了 translog,只有在 segment 数据落盘后,Elasticsearch 才会删除对应的 translog。
  • doc : doc 表示 lucene 中的一条记录。
  • field :field 表示记录中的字段概念,一个 doc 由若干个 field 组成。
  • term :term 是 lucene 中索引的最小单位,某个 field 对应的内容如果是全文检索类型,会将内容进行分词,分词的结果就是由 term 组成的。如果是不分词的字段,那么该字段的内容就是一个 term。
  • 倒排索引 (inverted index): lucene 索引的通用叫法,即实现了 term 到 doc list 的映射。

  • 正排数据:搜索引擎的通用叫法,即原始数据,可以理解为一个 doc list。
  • doc values:Elasticsearch 中的列式存储的名称,Elasticsearch 除了存储原始数据、倒排索引,还存储了一份 doc values,用作分析和排序。doc values 的存在是因为倒排索引只对某些操作是高效的。 倒排索引的优势在于查找包含某个项的文档,而对于从另外一个方向的相反操作并不高效,即:确定哪些项是否存在单个文档里,聚合需要这种次级的访问模式。

2. lucene 文件内容

lucene 包的文件是由很多 segment 文件组成的,segments_xxx 文件记录了 lucene 包下面的 segment 文件数量。每个 segment 会包含如下的文件。

一份数据写入 Elasticsearch 会产生多份数据用于不同查询方式,会比原数据占用更多磁盘空间。

对照上面的 lucene 文件表,进行简要归纳:

  • 存储原文 _source 的文件.fdt .fdm .fdx;
  • 存储倒排索引的文件.tim .tip .doc;
  • 用于聚合排序的列存文件.dvd .dvm;
  • 全文检索文件.pos .pay .nvd .nvm 等;
  • 加载到内存中的文件有.fdx .tip .dvm;

其中.tip 占用内存最大,而.fdt、.tim、.dvd 文件占用磁盘最大。