引言
在 Elasticsearch 的字段映射配置中,doc_values 是一个看似简单却影响深远的参数。许多开发者在使用 Elasticsearch 时都会遇到这样的困惑:为什么我的字段不能用于排序和聚合?为什么磁盘占用比预期大很多?这些问题的答案往往与 doc_values 的设置密切相关。本文将深入探讨 doc_values 的工作原理、适用场景以及最佳实践。
什么是 doc_values?
doc_values 是 Elasticsearch 中一种正排索引(forward index)的实现方式。与传统的倒排索引(invert index)不同:
- 倒排索引:记录"词项→文档"的映射,用于快速查找包含特定词项的文档
- 正排索引(doc_values) :记录"文档→词项"的映射,用于快速访问某个文档的字段值
// 默认情况下,大多数字段都启用 doc_values
{
"mappings": {
"properties": {
"product_name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"doc_values": true // 默认值
}
}
}
}
}
}
doc_values 的两种状态
1. doc_values: true(默认)
特点:
-
启用正排索引
-
允许字段用于:
- 排序(sort)
- 聚合(aggregation)
- 脚本中访问字段值
- 某些类型的联合查询
代价:
- 增加磁盘占用(通常增加原数据大小的10-25%)
- 轻微影响索引速度(约5-15%的性能下降)
2. doc_values: false
特点:
-
禁用正排索引
-
无法用于:
- 排序
- 聚合
- 脚本访问
-
仅能用于:
- 全文搜索
- 精确值匹配查询
优势:
- 减少磁盘占用
- 提高索引速度
- 降低内存压力
典型应用场景
应该启用 doc_values 的情况
-
需要排序的字段
json
GET /products/_search { "sort": [ { "price": { "order": "desc" } } ] } -
需要进行聚合分析的字段
json
GET /sales/_search { "aggs": { "categories": { "terms": { "field": "category.keyword" } } } } -
在脚本中需要访问字段值的场景
json
{ "script_fields": { "discounted_price": { "script": { "source": "doc['price'].value * 0.9" } } } }
可以考虑禁用 doc_values 的情况
-
仅用于搜索,从不用于分析的大文本字段
json
{ "mappings": { "properties": { "product_description": { "type": "text", "doc_values": false } } } } -
日志数据中仅用于过滤的字段
json
{ "mappings": { "properties": { "debug_level": { "type": "keyword", "doc_values": false } } } }最佳实践建议
-
遵循默认值
除非有明确需求,否则保持doc_values=true。Elasticsearch 的默认设置已经过充分优化。 -
针对特定场景优化
对于明确知道只需要查询而不需要分析的字段,可以设置为 false:{ "mappings": { "properties": { "session_id": { "type": "keyword", "doc_values": false, "index": true } } } } -
多字段(multi-fields)策略
对同一字段同时支持搜索和分析:{ "mappings": { "properties": { "product_name": { "type": "text", "fields": { "raw": { "type": "keyword", "doc_values": true } } } } } } -
监控与调整
使用 Elasticsearch 的监控 API 观察字段使用情况:GET /_stats/fielddata?fields=* GET /_cat/fielddata?v
常见问题解答
Q:禁用 doc_values 后还能搜索该字段吗?
A:可以!doc_values 只影响排序/聚合能力,不影响搜索功能。
Q:已经索引的数据能修改 doc_values 设置吗?
A:不能,必须重建索引。建议使用 reindex API。
Q:doc_values 和 fielddata 有什么区别?
A:两者都提供正排索引功能,但:
- doc_values 是磁盘-based,在索引时构建
- fielddata 是内存-based,在查询时动态构建
Q:如何知道哪些字段消耗了大量 doc_values 空间?
A:使用:
GET /_stats/fielddata?human&fields=*
结论
doc_values 是 Elasticsearch 中一个看似简单却影响深远的配置。合理设置可以:
- 在需要分析的字段上获得最佳性能
- 在不必要的字段上节省宝贵的磁盘空间
- 平衡索引速度和查询性能
记住黄金法则:如果你不确定,保持默认值。只有在明确了解字段使用场景后,才考虑禁用 doc_values。