← 返回题目列表

Elasticsearch 的 doc_values 和 fielddata 有什么区别?

高频 中等 第 5 / 30 题 更新于 2026/07/29
Elasticsearchdoc_valuesfielddata聚合

简化版

doc_values 是面向排序、聚合、脚本访问的列式磁盘结构,keyword、数字、日期等字段默认通常启用;fielddata 是 text 字段为了排序/聚合临时在堆内存中构建的结构,容易占用大量 JVM heap。生产中不要随便对 text 开 fielddata,通常用 .keyword 做聚合和排序。

详细版

倒排索引适合从 term 找文档,但排序和聚合经常要从文档找字段值。doc_values 就是为这种访问模式准备的列式结构,更多依赖磁盘和文件系统缓存。

text 字段默认没有 doc_values,因为它会分词;如果硬要对 text 排序或聚合,可能需要开启 fielddata,把 token 到文档的关系加载到 JVM heap,内存风险很高。面试回答抓住:查询检索看倒排,排序聚合看 doc_values;text 聚合优先用 keyword 子字段。

完整版教学

一、倒排索引不擅长排序和聚合

倒排索引回答的问题是:某个 term 出现在哪些文档里。

term "paid" -> doc1, doc7, doc9
term "new"  -> doc2, doc5

但排序和聚合经常反过来问:每个文档的字段值是什么。例如按价格排序、按状态分桶、计算每天订单数。

doc1 -> price = 99
doc2 -> price = 35
doc3 -> price = 120

这种“按文档读列值”的访问模式,正是 doc_values 的用武之地。

记忆钩子:倒排负责“词到文档”,doc_values 负责“文档到值”。

二、doc_values 是列式结构

doc_values 是一种列式存储结构,适合排序、聚合和脚本访问字段值。keyword、numeric、date、boolean、ip 等字段通常默认启用。

操作需要什么常用结构
全文检索term -> docs倒排索引
精确过滤term -> docs倒排索引
排序doc -> valuedoc_values
聚合doc -> valuedoc_values
脚本字段访问doc -> valuedoc_values

由于 doc_values 更多利用磁盘和操作系统页缓存,它比把大量数据塞进 JVM heap 更稳。

三、fielddata 为什么危险

text 字段被分词后,天然适合全文检索,不适合直接排序和聚合。为了让 text 字段也能按 token 做聚合,Elasticsearch 可以构建 fielddata。

问题在于 fielddata 通常加载到 JVM heap,数据量一大就可能触发频繁 GC,甚至 OOM。

1000 万文档
每个 title 平均 8 个 token
可能产生 8000 万级 token-doc 关系
加载到 heap 风险极高

所以线上看到错误提示让你开启 fielddata 时,不要机械照做,先检查是不是应该用 .keyword 字段。

四、为什么 text.keyword 是常见设计

多字段 mapping 可以让一个字段同时支持全文搜索和精确聚合。

{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

title 用于 match 全文搜索,title.keyword 用于 term 精确匹配、排序和聚合。

{ "terms": { "field": "title.keyword" } }

这是很多 ES 面试和生产排障的标准答案。

五、什么时候关闭 doc_values

doc_values 也不是完全没有成本。它会占用磁盘空间。如果某个字段只用于全文检索,不会排序、聚合、脚本访问,可以考虑关闭 doc_values。

但大多数场景不建议过早关闭,尤其是 keyword、日期、状态、类型字段,后续很可能会用于聚合或排序。

{
  "type": "keyword",
  "doc_values": false
}

这个配置一旦用于生产,要确认不会影响已有查询。否则后面临时要做聚合,会发现字段能力不够。

六、排查聚合内存问题的思路

如果 ES 聚合导致内存高,可以按下面检查:

1. 聚合字段是不是 text
2. 有没有误开 fielddata
3. 是否应该改用 keyword 子字段
4. terms 聚合桶数量是否过大
5. 是否需要 composite aggregation 分页
6. JVM heap 和 circuit breaker 是否报警

不要只盯着机器内存。ES 的 JVM heap、文件系统缓存和磁盘结构分工不同,fielddata 问题尤其容易把 heap 打爆。

七、常见误区与追问

  • 误区:倒排索引可以高效完成所有查询。 倒排适合检索,排序和聚合更依赖 doc_values。
  • 误区:text 字段聚合报错就直接开启 fielddata。 fielddata 可能大量占用 heap,通常应使用 keyword 子字段。
  • 误区:doc_values 在内存里,所以很危险。 doc_values 是列式磁盘结构,更多依赖文件系统缓存。
  • 追问:为什么 keyword 能聚合,text 不适合? keyword 保留整体值并有 doc_values,text 分词后语义不同。
  • 追问:fielddata 什么时候能用? 少量字段、明确 token 聚合需求、评估内存后才考虑。
  • 追问:ignore_above 会影响什么? 超过长度的 keyword 值可能不进入 keyword 子字段,聚合和精确查询会受影响。

八、加强记忆

doc_values 和 fielddata 记成“列式稳,堆内险”。检索靠倒排,排序聚合靠 doc_values;keyword、数字、日期天然适合,text 字段如果硬聚合会牵出 fielddata,容易吃 JVM heap。生产里优先用 .keyword 子字段做精确过滤、排序和聚合,只有非常明确的 token 聚合需求才考虑 fielddata。