为什么全局序数建立在字段数据而不是 doc_values 上?

sus*_*lov 2 lucene elasticsearch

我有一个像这样的字段“位置”

 "location": {
        "type": "string",
        "index": "not_analyzed",
        "store": true,
        "fielddata": {
          "format": "doc_values"
        }
      },
Run Code Online (Sandbox Code Playgroud)

但是,当我在这个字段中使用术语聚合时,我看到了这种日志

[2015-05-13 15:42:56.210][DEBUG][index.fielddata.plain] Global-ordinals[location][361372] took 206 ms
[2015-05-13 17:55:44.692][DEBUG][index.fielddata.plain] Global-ordinals[location][461584] took 230 ms
[2015-05-13 17:56:21.907][DEBUG][index.fielddata.plain] Global-ordinals[location][263096] took 1205 ms
Run Code Online (Sandbox Code Playgroud)

而且我还可以看到 Java 堆大小已经增加,这导致了很长的旧垃圾收集。

为什么 doc_values 字段使用 java 堆?因为我也存储它们?我可以避免垃圾收集吗?

Vin*_*han 5

全局序数是将字段中的每个唯一项映射到唯一编号的结构。这需要生成以便内存指纹和计算更好。

您可以在此处了解有关全局序数的更多信息。

这是此信息的摘要,以防此链接有一天失效:

全局序数

用于减少字符串字段数据内存使用的技术之一称为序数。

想象一下,我们有十亿个文档,每个文档都有一个status字段。只有三种状态:status_pending, status_published, status_deleted。如果我们将每个文档的完整字符串状态保存在内存中,我们将使用每个文档 14 到 16 个字节,或大约 15 GB。

相反,我们可以识别三个唯一的字符串,对它们进行排序和编号:0、1、2。

Ordinal | Term
-------------------
0       | status_deleted
1       | status_pending
2       | status_published
Run Code Online (Sandbox Code Playgroud)

原始字符串在序数列表中只存储一次,每个文档只使用编号的序数指向它包含的值。

Doc     | Ordinal
-------------------------
0       | 1  # pending
1       | 1  # pending
2       | 2  # published
3       | 0  # deleted
Run Code Online (Sandbox Code Playgroud)

这将内存使用量从 15 GB 减少到不到 1 GB!