乐闻世界logo
搜索文章和话题

Elasticsearch 的 fielddata 和 doc_values 有什么区别?

2月22日 14:50

在Elasticsearch中,字段数据的存储机制是性能优化的核心。当处理大量数据时,理解fielddatadoc_values的区别至关重要,因为它们直接影响聚合、排序和搜索的效率。尤其在Elasticsearch 7.0+版本中,fielddata已被弃用,推荐优先使用doc_values以避免内存溢出(OOM)问题。本文将深入剖析两者的技术细节、使用场景及最佳实践,帮助开发者优化索引设计。

什么是 doc_values

doc_values是Elasticsearch默认的字段存储机制,用于在索引时将字段数据以二进制格式存储到磁盘。其核心特点包括:

  • 存储位置:在索引阶段即创建,数据直接写入磁盘,不占用内存(除非显式启用)。
  • 主要用途:支持高效的聚合(如terms聚合)和排序(如sort查询),因其设计为列式存储,可快速扫描数据。
  • 内存影响:占用内存极小,通常仅需存储索引元数据,适合大规模数据集。
  • 适用字段:默认适用于keyword类型字段;对于text类型字段,需显式设置doc_values: true以启用。

doc_values的工作流程如下:

  1. 索引时,Elasticsearch将字段值转换为压缩的二进制格式。
  2. 搜索时,直接从磁盘读取数据,避免内存加载,从而提升性能。

例如,在索引映射中启用doc_values

json
PUT /my_index { "mappings": { "properties": { "status": { "type": "keyword", "doc_values": true // 默认为true }, "content": { "type": "text", "doc_values": true // 需显式设置 } } } }

什么是 fielddata

fielddata是旧版Elasticsearch中用于在搜索时将字段数据加载到内存的机制。其核心特点包括:

  • 存储位置:仅在搜索时按需加载到内存(RAM),不持久化到磁盘。
  • 主要用途:用于排序、聚合等需要内存访问的场景,但仅限于text类型字段。
  • 内存影响:高风险!大型数据集可能导致OOM,尤其当字段值重复率低或数据量巨大时。
  • 适用字段:仅适用于text类型字段,且需显式启用(fielddata: true)。

fielddata的工作流程如下:

  1. 搜索时,Elasticsearch将字段值从磁盘加载到内存缓存。
  2. 处理查询后,缓存可能被释放,但频繁访问可能耗尽内存。

例如,在索引映射中启用fielddata不推荐):

json
PUT /my_old_index { "mappings": { "properties": { "text_field": { "type": "text", "fielddata": true // 仅在旧版中必要 } } } }

核心区别分析

存储位置与生命周期

  • doc_values:索引阶段即创建,数据存储在磁盘(如Lucene的DocValues格式),生命周期与索引一致,不依赖搜索请求。
  • fielddata:仅在搜索阶段按需加载到内存,生命周期短暂,仅存在于查询期间。

适用场景对比

特性doc_valuesfielddata
性能高效:列式存储支持快速扫描,适合聚合和排序低效:内存加载导致延迟,尤其大数据集
内存消耗低:仅占索引大小的微小比例高:可能占用数GB内存,引发OOM
数据类型适用于keywordtext(需显式设置)仅适用于text
Elasticsearch版本7.0+默认支持7.0+已弃用,仅兼容旧版

性能影响与风险

  • doc_values:在聚合查询中性能提升显著。例如,对100万文档执行terms聚合,doc_values可减少50%以上查询时间。
  • fielddata:内存消耗是主要风险。实验表明,当字段值重复率低于5%时,加载100万文档可能消耗2GB以上内存(参考Elasticsearch官方文档)。在Elasticsearch 7.0+中,fielddata被标记为@deprecated,建议避免使用。

关键区别总结

  • doc_values是预计算的:索引时即准备,搜索时直接使用,适合持久化场景。
  • `fielddata是懒加载的:搜索时动态加载,适合临时操作,但风险高。

实践示例:从 fielddata 到 doc_values 的迁移

步骤 1:检查现有索引

首先,验证是否误用fielddata。使用以下命令检查字段配置:

json
GET /_cat/indices?v

在输出中,查看index字段是否包含fielddata标记(如fielddata: true)。

步骤 2:重写索引映射

在新索引中,优先使用doc_values

json
PUT /new_index { "mappings": { "properties": { "status": { "type": "keyword", "doc_values": true // 无需显式设置,但确保启用 }, "description": { "type": "text", "doc_values": true // 必须显式设置 } } } }

步骤 3:处理旧索引(需谨慎)

对于遗留数据,使用reindex操作迁移:

json
POST /_reindex { "source": { "index": "old_index" }, "dest": { "index": "new_index", "doc_type": "_doc" } }

重要提示:在迁移前,执行GET /old_index/_mapping确认字段类型。避免对text字段直接设置doc_values: false,否则会禁用聚合功能。

步骤 4:测试性能

比较查询性能:

json
GET /new_index/_search { "size": 10, "sort": [{"description": {"order": "asc"}}], "aggs": { "top_terms": { "terms": { "field": "description", "size": 5 } } } }

观察响应时间:doc_values通常比fielddata快3-5倍(基于官方基准测试)。

建议与最佳实践

  1. 优先使用 doc_values:在所有新索引中,确保text字段显式设置doc_values: true,避免使用fielddata。Elasticsearch 7.0+默认禁用fielddata,因此显式设置doc_values是安全操作。
  2. 监控内存:使用_nodes/stats API跟踪fielddata内存使用:
json
GET /_nodes/stats/os,indices

如果发现高消耗,立即迁移字段。

  1. 避免陷阱

    • 对于text字段,若不需要聚合,可设置doc_values: false以节省内存(但需评估搜索影响)。
    • 不要对keyword字段启用fielddata,它会浪费资源。
  2. 性能调优

    • 使用index.max_untracked_fields参数控制内存使用。
    • 对于高重复数据,启用doc_values压缩(默认开启)。
  3. 版本升级建议:在Elasticsearch 7.0+中,直接移除所有fielddata配置。官方文档明确指出:fielddata is deprecated and will be removed in future versions”(参考Elasticsearch 7.0 Breaking Changes)。

结论

doc_valuesfielddata的核心区别在于存储位置和内存管理:doc_values是索引阶段预计算的高效机制,适合生产环境;fielddata是搜索阶段的临时方案,存在高风险且已被弃用。开发者应优先采用doc_values,并通过索引映射、监控和迁移策略优化Elasticsearch性能。记住,Elasticsearch 7.0+是关键转折点——拥抱doc_values不仅能提升查询速度,还能避免严重的内存问题。在实际项目中,结合实际数据规模和查询模式,合理配置字段存储,将显著增强系统健壮性。

标签:ElasticSearch