当前位置: 代码网 > it编程>游戏开发>ar > Elasticsearch 查询核心概念详解

Elasticsearch 查询核心概念详解

2026年09月20日 ar 我要评论
1. doc_values概念doc_values 是 elasticsearch 在索引时(index time)构建的一种列式存储(column-oriented store)数据结构,存储在磁盘

1. doc_values

概念

doc_values 是 elasticsearch 在索引时(index time)构建的一种列式存储(column-oriented store)数据结构,存储在磁盘上。

它以文档 → 字段值的映射方式存储数据,但在物理层面是按列组织的,非常适合需要"遍历某个字段所有文档值"的操作。

工作原理

倒排索引(用于全文搜索):
  "apple" → [doc1, doc3, doc7]
  "banana" → [doc2, doc5]
doc_values(列式存储,用于聚合/排序):
  doc1 → "apple"
  doc2 → "banana"
  doc3 → "apple"

支持的字段类型

支持 doc_values不支持 doc_values
keywordtext
numeric(long/integer/float…)annotated_text
date
boolean
ip
geo_point

text 类型不支持 doc_values,因为 text 经过分词,原始值已碎片化。

使用场景

  • 排序(sort):按某字段排序文档
  • 聚合(aggregations):terms agg、range agg、avg/sum 等
  • 脚本访问(script):在脚本中通过 doc['field'].value 访问

配置示例

put /my_index
{
  "mappings": {
    "properties": {
      "price": {
        "type": "double",
        "doc_values": true   // 默认为 true,可显式关闭
      },
      "description": {
        "type": "keyword",
        "doc_values": false  // 若不需要排序/聚合,关闭可节省磁盘
      }
    }
  }
}

性能特点

  • 磁盘存储:持久化到磁盘,os 缓存负责热数据加速
  • 堆内存友好:不占用 jvm 堆,适合大数据量场景
  • 索引速度略降:需要在写入时额外构建列式结构

2. fielddata

概念

fielddata 是 elasticsearch 针对 text 类型字段的一种**运行时(query time)**内存数据结构,用于支持对 text 字段进行排序和聚合。

由于 text 字段经过分词,无法直接使用 doc_values,因此 es 在查询时将倒排索引"反转"成列式结构,加载到 jvm 堆内存中。

为什么默认禁用

  • 对 text 字段做聚合/排序通常语义错误(你可能想要的是原始值而非分词后的 token)
  • 首次加载时需要全量扫描分片,延迟极高
  • 驻留在 jvm 堆,内存压力大,可能触发 oom 或 gc 抖动

启用方式

put /my_index/_mapping
{
  "properties": {
    "content": {
      "type": "text",
      "fielddata": true   // 慎用!明确知道自己在做什么时才开启
    }
  }
}

推荐替代方案

与其开启 text 的 fielddata,更推荐:

{
  "properties": {
    "title": {
      "type": "text",          // 用于全文搜索
      "fields": {
        "keyword": {
          "type": "keyword"    // 用于聚合/排序,利用 doc_values
        }
      }
    }
  }
}

查询时使用 title.keyword 进行聚合或排序。

fielddata 内存控制

# elasticsearch.yml
indices.fielddata.cache.size: 20%   # 限制 fielddata 缓存最大占堆比例

超出限制时,es 会驱逐最久未使用的 fielddata 缓存。

3. doc_values vs fielddata 对比

维度doc_valuesfielddata
构建时机索引时(index time)查询时(query time)
存储位置磁盘(os page cache 加速)jvm 堆内存
适用字段keyword、numeric、date 等text(不推荐)
默认状态默认开启默认关闭
内存影响几乎不占堆直接占用 jvm 堆
首次访问延迟低(已在磁盘)高(需运行时构建)
推荐程度✅ 推荐⚠️ 慎用

核心结论:能用 doc_values 就用 doc_values;text 字段需要聚合时,用 fields 多字段映射加一个 keyword 子字段。

4. global ordinals

概念

global ordinals 是 elasticsearch 在 keyword 字段(以及开启 fielddata 的 text 字段)上建立的一种全局序号映射,用于加速 terms aggregation 等操作。

问题背景

lucene 段(segment)级别存在局部序号(local ordinals):

segment 1: { "apple"→0, "banana"→1, "cherry"→2 }
segment 2: { "apple"→0, "date"→1 }

跨段做 terms aggregation 时,需要将各段的 local ordinals 映射到统一的全局序号,这就是 global ordinals 的作用:

global ordinals:
  "apple"  → 0
  "banana" → 1
  "cherry" → 2
  "date"   → 3

构建时机

  • 默认(lazy 加载):第一次对该字段执行 terms aggregation 时,es 构建 global ordinals,并缓存在内存中(堆外,使用 lucene 的 off-heap 结构)
  • eager_global_ordinals:可配置为在 refresh 时立即构建,适合高频聚合场景

配置示例

put /my_index
{
  "mappings": {
    "properties": {
      "category": {
        "type": "keyword",
        "eager_global_ordinals": true   // refresh 时立即构建,减少首次查询延迟
      }
    }
  }
}

性能影响

场景建议
高基数字段(cardinality 高,如 user_id)谨慎使用 eager,构建成本高
低基数字段(如 status、category)推荐 eager_global_ordinals
写多读少(如日志索引)不必 eager
读多写少(如维度表)eager_global_ordinals 收益显著

与 terms aggregation 的关系

terms aggregation 的核心流程:

1. 利用 global ordinals 将每个文档的字段值映射为整数 id
2. 用整数数组统计每个 ordinal 的文档数
3. 选出 top-n ordinals
4. 将 ordinal 反查回原始字符串值

使用整数运算替代字符串比较,大幅提升聚合性能。

5. collapse(字段折叠)

概念

collapse 是 elasticsearch 的搜索去重功能,允许在搜索结果中按某个字段的值折叠(去重),每个唯一值只保留得分最高的文档。

类似于 sql 中的 group by + 取最优记录,但底层实现完全不同。

基础用法

get /my_index/_search
{
  "query": {
    "match": { "title": "elasticsearch" }
  },
  "collapse": {
    "field": "user_id"   // 按 user_id 折叠,每个用户只返回一条
  },
  "sort": [
    { "score": "desc" }  // 保留得分最高的文档
  ]
}

inner_hits:展开被折叠的文档

get /my_index/_search
{
  "collapse": {
    "field": "user_id",
    "inner_hits": {
      "name": "top_posts",     // inner_hits 的名称
      "size": 3,               // 每个折叠组展开显示 3 条
      "sort": [{ "date": "desc" }]
    }
  }
}

返回结构:

{
  "hits": [
    {
      "_source": { "user_id": "u1", "title": "..." },
      "inner_hits": {
        "top_posts": {
          "hits": { "hits": [ ... ] }   // 该 user 的 top 3 文档
        }
      }
    }
  ]
}

多级 collapse(es 7.x+)

{
  "collapse": {
    "field": "user_id",
    "inner_hits": {
      "name": "by_category",
      "collapse": { "field": "category" },   // 二级折叠
      "size": 5
    }
  }
}

约束与限制

限制项说明
字段要求折叠字段必须是 keyword、numeric 或 date 类型,且开启 doc_values
不影响聚合total_hits 统计的是折叠的文档总数,聚合也在折叠前的文档集上执行
不支持 scrollcollapse 与 scroll api 不兼容
不支持 rescorecollapse 后不能再 rescore
分页行为from + size 针对折叠后的结果计数

典型应用场景

  • 商品搜索:同一 spu 下多个 sku,只展示最相关的一个
  • 新闻聚合:同一话题/来源只展示一篇
  • 用户行为:同一用户的多条日志只展示最新/最高分一条

6. track_total_hits

概念

track_total_hits 控制 elasticsearch 在搜索响应中如何统计命中总数hits.total)。

背景

精确统计文档总数(如:共找到 1,234,567 条结果)在大数据集上代价很高,因为 es 需要遍历所有匹配文档。elasticsearch 7.0 起引入此参数来提供灵活控制。

参数取值

类型含义
trueboolean精确统计,返回真实 total(relation: “eq”)
falseboolean完全不统计,total 返回 -1(性能最优)
n(正整数)integer当总数 ≤ n 时精确统计;超过 n 时返回 ≥ n 的近似值(relation: “gte”)

默认值10000(es 7.0+)

示例

get /my_index/_search
{
  "track_total_hits": true,   // 精确统计所有文档
  "query": { "match_all": {} }
}

响应:

{
  "hits": {
    "total": {
      "value": 1234567,
      "relation": "eq"     // 精确值
    }
  }
}

使用默认值(10000)时,若超过 10000:

{
  "hits": {
    "total": {
      "value": 10000,
      "relation": "gte"    // 表示"至少 10000 条"
    }
  }
}

性能影响

track_total_hits=false      → 跳过 total 统计,最快
track_total_hits=10000      → 默认,超过阈值后停止精确计数
track_total_hits=true       → 全量遍历,数据量大时最慢

实践建议

场景推荐配置
只关心前几页结果,不显示"共 x 条"false 或较小的整数
显示"约 x 条"近似数即可默认 10000
需要精确分页总数(如后台管理)true
深度分页 + 大数据集search_after 替代传统分页,配合 false

综合对比速查表

概念阶段核心作用存储位置注意事项
doc_values索引时排序、聚合、脚本访问磁盘默认开启,text 不支持
fielddata查询时text 字段聚合/排序jvm 堆慎用,推荐用 keyword 子字段替代
global ordinalsrefresh 时 / 首次查询时加速 terms aggregation内存(off-heap)高基数字段谨慎开启 eager
collapse查询时搜索结果去重/折叠字段需开启 doc_values
track_total_hits查询时控制 total 统计精度大数据集避免设为 true

延伸阅读

到此这篇关于elasticsearch 查询核心概念详解的文章就介绍到这了,更多相关elasticsearch 查询内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com