Elasticsearch字段属性:doc_values

101 阅读3分钟

引言

在 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 的情况

  1. 需要排序的字段

    json

    GET /products/_search
    {
      "sort": [
        { "price": { "order": "desc" } }
      ]
    }
    
  2. 需要进行聚合分析的字段

    json

    GET /sales/_search
    {
      "aggs": {
        "categories": {
          "terms": { "field": "category.keyword" }
        }
      }
    }
    
  3. 在脚本中需要访问字段值的场景

    json

    {
      "script_fields": {
        "discounted_price": {
          "script": {
            "source": "doc['price'].value * 0.9"
          }
        }
      }
    }
    

可以考虑禁用 doc_values 的情况

  1. 仅用于搜索,从不用于分析的大文本字段

    json

    {
      "mappings": {
        "properties": {
          "product_description": {
            "type": "text",
            "doc_values": false
          }
        }
      }
    }
    
  2. 日志数据中仅用于过滤的字段

    json

    {
      "mappings": {
        "properties": {
          "debug_level": {
            "type": "keyword",
            "doc_values": false
          }
        }
      }
    }
    

    最佳实践建议

  3. 遵循默认值
    除非有明确需求,否则保持 doc_values=true。Elasticsearch 的默认设置已经过充分优化。

  4. 针对特定场景优化
    对于明确知道只需要查询而不需要分析的字段,可以设置为 false:

    {
      "mappings": {
        "properties": {
          "session_id": {
            "type": "keyword",
            "doc_values": false,
            "index": true
          }
        }
      }
    }
    
  5. 多字段(multi-fields)策略
    对同一字段同时支持搜索和分析:

    {
      "mappings": {
        "properties": {
          "product_name": {
            "type": "text",
            "fields": {
              "raw": {
                "type": "keyword",
                "doc_values": true
              }
            }
          }
        }
      }
    }
    
  6. 监控与调整
    使用 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。