Elasticsearch 的 fielddata 和 doc_values 有什么区别?
fielddata 是基于 JVM 堆内存的倒排索引补充结构,仅在搜索时按需加载到内存,专用于 text 字段的聚合和排序,内存消耗不可控,易引发 OOM;doc_values 是基于磁盘的列式存储,索引时随文档写入持久化,默认对 keyword 和数值类型启用,不占堆内存,ES 5.x 后成为默认方案。核心区别:存储位置(堆 vs 磁盘)、加载时机(搜索时 vs 索引时)、内存风险(高 vs 低)、适用类型(text vs keyword/numeric)。生产环境中应优先用 doc_values,若字段不需聚合/排序可关闭 doc_values 节省磁盘。
追问
为什么 fielddata 容易 OOM?
fielddata 将字段的全部唯一词项加载到 JVM 堆,高基数字段(如 UUID)可能占用数 GB。且被 LRU 缓存持有,不会主动释放,直到触发 circuit breaker。
text 字段需要聚合怎么办?
推荐用 multi-fields:主字段 text 做全文检索,子字段 keyword 启用 doc_values 做聚合。避免在 text 上开启 fielddata: true。
关闭 doc_values 有什么影响?
该字段将无法用于聚合、排序和脚本访问。如果字段只做全文检索不需要这些操作,关闭可节省约 10-15% 磁盘空间。
doc_values 的列式存储如何加速聚合?
列式存储按字段值连续排列,对同一字段的遍历只需顺序读磁盘,CPU 缓存命中率高。行式存储需跳行读取,I/O 散乱。
ES 7.x 后还有必要了解 fielddata 吗?
需要。排查旧索引的内存问题时仍需检查 fielddata 占用,GET _nodes/stats/indices?fielddata 可定位高消耗字段。
写段代码
jsonPUT /products { "mappings": { "properties": { "title": { "type": "text", "fields": { "keyword": { "type": "keyword", "doc_values": true } } }, "status": { "type": "keyword", "doc_values": true } } } }