Skip to content

磁盘使用量优化

优化磁盘使用量与建立索引时的映射参数和索引元数据字段密切相关

预备知识

元数据字段

每个文档都有与其相关的元数据,比如_index、_type 和_id。当创建映射类型时,可以定制其中一些元数据字段。

  • _source:原始的JSON文档数据。
  • _all:索引所有其他字段值的一种通用字段,这个字段中包含了所有其他字段的值。

索引映射参数

  • index:控制字段值是否被索引。它可以设置为true或false,默认为true。未被索引的字段不会被查询到,但是可以聚合。除非禁用doc_values。
  • doc values:默认情况下,大多数字段都被索引,这使得它们可以搜索。倒排索引根据term找到文档列表,然后获取文档原始内容。但是排序和聚合,以及从脚本中访问某个字段值,需要不同的数 据访问模式,它们不仅需要根据term找到文档,还要获取文档中字段 的值。这些值需要单独存储。doc_values 就是用来存储这些字段值 的。它是一种存储在磁盘上的列式存储,在文档索引时构建,这使得 上述数据访问模式成为可能。它们以面向列的方式存储与_source相同 的值,这使得排序和聚合效率更高。几乎所有字段类型都支持 doc_values,但被分析(analyzed)的字符串字段除外(即text类 型字符串)。doc_values默认启用。
  • store:默认情况下,字段值会被索引使它们能搜索,但它们不 会被存储(stored)。意味着可以通过这个字段查询,但不能取回它 的原始值。

但这没有关系。因为字段值已经是_source字段的一部分,它是被 默认存储的。如果只想取回一个字段或少部分字段的值,而不是整个 _source,则可以通过source filtering达到目的。

在某些情况下,存储字段是有意义的。例如,如果有一个包含标 题、日期和非常多的内容字段的文档,则可能希望只检索标题和日 期,而不需要从大型_source字段中提取这些字段

还有一种情况可能用到存储字段,就是不在_source中出现的字段 (例如,copy_to字段)。 doc_values和存储字段("stored":ture)都属于正排内容, 两者的设计初衷不同。

stored fields被设计为优化存储,doc_values被设计为快速访问 字段值。搜索可能会访问很多doc values中的字段,所以必须能够快 速访问,我们将doc_values用于聚合、排序,以及脚本中。现在,ES 中的许多特性都会自动使用doc_values。

另一方面,存储字段仅用于返回前几个最匹配文档的字段值,默 认情况下 ES 只将其用于这种情况,解压存储字段,将其发送给客户 端。为少量文档获取存储字段还好。它不能在查询的时候使用,否则 会让查询变得非常慢。脚本中可以访问存储字段,但最好不要那么 做。

优化措施

禁用对你来说不需要的特性

默 认 情 况 下 , ES 为 大 多 数 的 字 段 建 立 索 引 , 并 添 加 到 doc_values,以便使之可以被搜索和聚合。但是有时候不需要通过某 些字段过滤,例如,有一个名为 foo 的数值类型字段,需要运行直方 图,但不需要在这个字段上过滤,那么可以不索引这个字段:

text 类型的字段会在索引中存储归一因子(normalization factors),以便对文档进行评分,如果只需要在文本字段上进行匹 配,而不关心生成的得分,则可以配置 ES 不将 norms 写入索引:

text类型的字段默认情况下也在索引中存储频率和位置。频率用 于计算得分,位置用于执行短语(phrase)查询。如果不需要运行短 语查询,则可以告诉ES不索引位置:

在text类型的字段上,index_options的默认值为positions。 index_options参数用于控制添加到倒排索引中的信息。 freqs 文档编号和词频被索引,词频用于为搜索评分,重复出现的 词条比只出现一次的词条评分更高。positions 文档编号、词频和位置 被索引。位置被用于邻近查询(proximity queries)和短语查询 (phrase queries)。

此外,如果也不关心评分,则可以将ES配置为只为每个term索引 匹配的文档。仍然可以在这个字段上搜索,但是短语查询会出现错 误,评分将假定在每个文档中只出现一次词汇。

禁用doc values

所有支持doc value的字段都默认启用了doc value。如果确定不 需要对字段进行排序或聚合,或者从脚本访问字段值,则可以禁用doc value以节省磁盘空间

不要使用默认的动态字符串映射

默认的动态字符串映射会把字符串类型的字段同时索引为 text 和 keyword。如果只需要其中之一,则显然是一种浪费。通常,id字段 只需作为 keyword类型进行索引,而body字段只需作为text类型进 行索引。 要禁用默认的动态字符串映射,则可以显式地指定字段类型,或 者在动态模板中指定将字符串映射为text或keyword。

观察分片大小

较大的分片可以更有效地存储数据。为了增加分片大小,可以在 创建索引的时候设置较少的主分片数量,或者使用shrink API来修改 现有索引的主分片数量。但是较大的分片也有缺点,例如,较长的索 引恢复时间

禁用_source

_source 字段存储文档的原始内容。如果不需要访问它,则可以 将其禁用。但是,需要访问_source的API将无法使用,至少包括下列 情况:

· update、update_by_query、reindex;
· 高亮搜索;
· 重建索引(包括更新mapping、分词器,或者集群跨大版本升级可能会用到);
· 调试聚合查询功能,需要对比原始数据。

使用best_compression

_source和设置为"store": true的字段占用磁盘空间都比较 多。默认情况下,它们都是被压缩存储的。默认的压缩算法为LZ4,可 以 通 过 使 用 best_compression 来 执 行 压 缩 比 更 高 的 算 法 : DEFLATE。但这会占用更多的CPU资源。

Fource Merge

一个ES索引由若干分片组成,一个分片有若干Lucene分段,较大 的Lucene分段可以更有效地存储数据。 使用_forcemerge API来对分段执行合并操作,通常,我们将分 段合并为一个单个的分段:max_num_segments=1

Shrink Index

Shrink API允许减少索引的分片数量,结合上面的Force Merge API,可以显著减少索引的分片和Lucene分段数量。

数值类型长度够用就好

为数值类型选择的字段类型也可能会对磁盘使用空间产生较大影 响,整型可以选择 byte、short、integer或 long,浮点型可以选择 scaled_float、float、double、half_float,每个数据类型的字节长 度是不同的,为业务选择够用的最小数据类型,可以节省磁盘空间。

使用索引排序来排列类似的文档

当 ES 存储_source 时,它同时压缩多个文档以提高整体压缩 比。例如,文档共享相同的字段名,或者它们共享一些字段值,特别 是 在 具 有 低 基 数 或 zipfian 分 布 ( 参 考 https://en.wikipedia.org/wiki/Zipf's_law)的字段上。 默认情况下,文档按照添加到索引中的顺序压缩在一起。如果启 用了索引排序,那么它们将按排序顺序压缩。对具有相似结构、字段 和值的文档进行排序可以提高压缩比。 关 于 索 引 排 序 的 详 细 内 容 请 参 考 官 方 手 册 : https://www.elastic.co/guide/en/elasticsearch/reference/mast er/index-modules-index-sorting.html。

在文档中以相同的顺序放置字段

由于多个文档被压缩成块,如果字段总是以相同的顺序出现,那 么在这些_source文档中可以找到更长的重复字符串的可能性更大。

Released under the MIT License.