es fielddata 及 doc_values 理解

Doc values 不支持 analyzed 字符串字段,因为它们不能很有效的表示多值字符串。 Doc values 最有效的是,当每个文档都有一个或几个 tokens 时, 但不是无数的,分析字符串(想象一个 PDF ,可能有几兆字节并有数以千计的独特 tokens)。

出于这个原因,doc values 不生成分析的字符串,然而,这些字段仍然可以使用聚合,那怎么可能呢?

答案是一种被称为 fielddata 的数据结构。与 doc values 不同,fielddata 构建和管理 100% 在内存中,常驻于 JVM 内存堆。这意味着它本质上是不可扩展的,有很多边缘情况下要提防。 本章的其余部分是解决在分析字符串上下文中 fielddata 的挑战。

高基数内存的影响(High-Cardinality Memory Implications)

避免分析字段的另外一个原因就是:高基数字段在加载到 fielddata 时会消耗大量内存。 分析的过程会经常(尽管不总是这样)生成大量的 token,这些 token 大多都是唯一的。 这会增加字段的整体基数并且带来更大的内存压力。

因此,在聚合字符串字段之前,请评估情况:

  • 这是一个 not_analyzed 字段吗?如果是,可以通过 doc values 节省内存 。
  • 否则,这是一个 analyzed 字段,它将使用 fielddata 并加载到内存中。这个字段因为 ngrams 有一个非常大的基数?如果是,这对于内存来说极度不友好。

限制内存使用

一旦分析字符串被加载到 fielddata ,他们会一直在那里,直到被驱逐(或者节点崩溃)。由于这个原因,留意内存的使用情况,了解它是如何以及何时加载的,怎样限制对集群的影响是很重要的。

Fielddata 是 延迟 加载。如果你从来没有聚合一个分析字符串,就不会加载 fielddata 到内存中。此外,fielddata 是基于字段加载的, 这意味着只有很活跃地使用字段才会增加 fielddata 的负担。

然而,这里有一个令人惊讶的地方。假设你的查询是高度选择性和只返回命中的 100 个结果。大多数人认为 fielddata 只加载 100 个文档。

实际情况是,fielddata 会加载索引中(针对该特定字段的) 所有的 文档,而不管查询的特异性。逻辑是这样:如果查询会访问文档 X、Y 和 Z,那很有可能会在下一个查询中访问其他文档。

与 doc values 不同,fielddata 结构不会在索引时创建。相反,它是在查询运行时,动态填充。这可能是一个比较复杂的操作,可能需要一些时间。 将所有的信息一次加载,再将其维持在内存中的方式要比反复只加载一个 fielddata 的部分代价要低。

JVM 堆 是有限资源的,应该被合理利用。 限制 fielddata 对堆使用的影响有多套机制,这些限制方式非常重要,因为堆栈的乱用会导致节点不稳定(感谢缓慢的垃圾回收机制),甚至导致节点宕机(通常伴随 OutOfMemory 异常)。

详细内容参看:https://www.elastic.co/guide/cn/elasticsearch/guide/current/_closing_thoughts.html