Elasticsearch `_search` API Query DSL、性能开关与实战范式

发布于:2025-08-14 ⋅ 阅读:(14) ⋅ 点赞:(0)

1. _search 是什么?

_search 用来在 索引/数据流 上执行查询与聚合,请求体用 Query DSL(JSON)编写。返回值里 hits.hits 是前 N 条结果(默认 10 条)。(Elastic)

最小示例:

GET /my-index-000001/_search
{
  "query": {
    "match": { "user.id": "kimchy" }
  }
}

这会按相关性(_score)返回 top10。(Elastic)

2. Query DSL 基础与组合

  • 全文查询match / multi_match 面向分析后的文本;
  • 词项级(精确)查询term/terms/range 适合过滤;
  • 布尔组合boolmust/should/filter/must_notfilter 不计分、可缓存,适合“先过滤后打分”。(Elastic)

3. 常用能力清单(带实用片段)

3.1 同时搜多个索引/数据流

支持 逗号分隔通配

GET /logs-2025.08-*,metrics-*/_search

也可以对某些索引加权(indices_boost)。(Elastic)

3.2 只取需要的字段

默认每条命中都会返回完整 _source。若只需少量字段,建议用 _source include 或 fields:(Elastic)

{
  "_source": ["@timestamp","message","user.id"],
  "fields": ["computed_runtime_field"]        // 运行时字段用 fields 取值
}

3.3 排序与打分

默认按 _score。要按业务字段排序,用 sort;需要自定义相关性,可用 script_score(注意性能)。(Elastic)

3.4 分页三件套

  • from/size:简单但大页会慢;
  • search_after:深分页推荐,基于上页最后一条的 sort 值;
  • scroll:离线批量遍历用,实时搜索不建议。(Elastic)

3.5 运行时字段:查询里“临时造字段”

不改 mapping,也能在查询期临时定义字段并参与聚合/过滤:(Elastic)

GET /my-index/_search
{
  "runtime_mappings": {
    "day_of_week": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
      }
    }
  },
  "aggs": {
    "by_dow": { "terms": { "field": "day_of_week" } }
  }
}

3.6 超时与取消

  • timeout:给每个分片一个收集时间上限;到期用已收集到的命中返回(适合低延迟优先)。(Elastic)
  • 取消:HTTP 连接断开或通过 Task Management 取消任务。(Elastic)

3.7 track_total_hits:命中数精度 vs 性能

  • 默认精确到 10,000,超过则返回“下界”(relation: "gte");
  • 设为 true 得到精确总数(禁用 MaxWAND,更慢);
  • 也可设整数阈值(如 100),精确计到该阈值即可。(Elastic)
{ "track_total_hits": 100, "query": { "match": { "user.id": "elkbee" } } }

3.8 只想知道“有没有命中”

最快路径:size: 0 + (可选) terminate_after: 1(每分片找到第一条就停)。注意 terminate_after 有使用注意,尽量让 ES 自动提前终止;跨多温层数据流时不要用。(Elastic)

GET /_search?q=user.id:elkbee&size=0&terminate_after=1

3.9 异步搜索:长查询的标配

大数据量或跨多集群用 Async Search:先提交、拿到 id,随后轮询获取阶段性/最终结果。可用 wait_for_completion_timeout 把“提交与等待”合成一步。(Elastic)

POST /my-index-*/_async_search?wait_for_completion_timeout=2s&keep_alive=10m
{ "query": { "range": { "@timestamp": { "gte": "now-1h" } } } }

GET  /_async_search/<id>

4. “一眼看懂”选型与性能开关

目标 推荐做法
高频在线检索 bool + filter 先过滤后打分;只取需要字段;限制 from+size
深分页 使用 search_after,避免 from 很大
实时聚合 尽量聚合小范围数据;必要时用 timeout 防长尾
要精确总数 track_total_hits: true(注意性能)或设一个合理上限值
仅判断是否存在 size: 0 +(可选)terminate_after
查询期造临时字段 runtime_mappings + fields 取值
长耗时查询 _async_search + keep_alive,前台不阻塞

参考项见官方 _search、Query DSL、runtime fields、Async Search 文档。(Elastic)

5. 实战范式:日志检索(含聚合与分页)

GET /logs-2025.08-*/_search
{
  "track_total_hits": 1000,
  "_source": ["@timestamp","service.name","message","trace.id"],
  "query": {
    "bool": {
      "filter": [
        { "range": { "@timestamp": { "gte": "now-15m" } } },
        { "term":  { "service.env": "prod" } }
      ],
      "must": [
        { "simple_query_string": { "query": "\"timeout\" | \"latency\"", "fields": ["message^2","error.message"] } }
      ]
    }
  },
  "aggs": {
    "top_services": { "terms": { "field": "service.name", "size": 10 } }
  },
  "sort": [{ "@timestamp": "desc" }],
  "size": 50
}
  • 过滤放 filter,全文匹配放 must
  • 既要列表又要统计,用聚合;
  • 需要深翻页时,把 sort 的最后一条带回做 search_after。(Elastic)

6. 常见坑位与排雷

  • 把过滤写成打分mustterm/range 也会参与评分,推荐放 filter。(Elastic)
  • 过度追求精确总数track_total_hits: true 会牺牲性能,评估业务是否真的需要。(Elastic)
  • terminate_after 滥用:官方建议谨慎,避免多层数据流/大范围;让 ES 自行早停更稳。(Elastic)
  • 大页 from:越往后越慢;用 search_after。(Elastic)
  • 长查询阻塞前端:改用 _async_search,并合理设置 keep_alivewait_for_completion_timeout。(Elastic)

7. 收尾

_search 玩明白,关键是三件事:写好 Query DSL只拿必要数据用对性能开关。线上一旦出现慢查/长尾,用 timeout 或转 _async_search,同时从过滤建模、索引/分片设计与缓存命中率几路并进优化。需要的话,我可以根据你的业务字段给一份 查询模板 + 指标看板(took/timeout/命中率) 的落地清单。


网站公告

今日签到

点亮在社区的每一天
去签到