5.1 搜索请求解剖:Search API 的结构 本节摘要:搜索请求(Search API)是命中之路的起点:协调节点解析请求,把查询扇出到相关分片,分片各自执行并返回本地前 N 条,协调节点归并后再取回原文——这就是"query then fetch"两阶段模型。本节拆解请求骨架、两阶段细节、响应字段的读法与超时、路由等参数,为后两节的 DSL 与结果整理搭好舞台。 一次查询的解剖 最小可用的搜索 请求体四件套:query 是灵魂;size 与 from 管窗口;source 管取回哪些字段——它们各自独立,产品列表页三件套齐上。路径里的 tickets 限定目标索引,也可以逗号分隔多个索引、通配符匹配一组按月滚动的索引,甚至跨集群搜索(那是第 7 章之后的远行)。
本节摘要:搜索请求(Search API)是命中之路的起点:协调节点解析请求,把查询扇出到相关分片,分片各自执行并返回本地前 N 条,协调节点归并后再取回原文——这就是"query then fetch"两阶段模型。本节拆解请求骨架、两阶段细节、响应字段的读法与超时、路由等参数,为后两节的 DSL 与结果整理搭好舞台。
GET tickets/_search { "query": { "match": { "title": "退款" } }, "size": 10, "from": 0, "_source": ["ticket_id", "title", "status"] }
请求体四件套:query 是灵魂;size 与 from 管窗口;_source 管取回哪些字段——它们各自独立,产品列表页三件套齐上。路径里的 tickets 限定目标索引,也可以逗号分隔多个索引、通配符匹配一组按月滚动的索引,甚至跨集群搜索(那是第 7 章之后的远行)。

图里藏着深分页的病根:要第 100 页(from 990),每个分片得回 1000 条候选,协调节点归并 3000 条再丢掉 2990 条——翻得越深,白干越多。5.3 会给出三个替代方案,此处先按下。
{ "took": 12, "timed_out": false, "hits": { "total": { "value": 137, "relation": "eq" }, "max_score": 3.712, "hits": [ { "_index": "tickets", "_id": "doc-1041", "_score": 3.712, "_source": { "title": "退款迟迟未到账" }, "highlight": { "title": ["退款迟迟未到账"] } } ] } }
took 是毫秒耗时;timed_out 为 true 时结果可能是部分的——超时只保证停止等待,不保证完整。total 在一万以内默认精确计数,超过后变模糊(relation 标 gte),要精确数得开计数追踪或直接用 8.1 的计数接口。max_score 与 _score 是相关性得分,纯 filter 查询没有分数,_score 为 null——看到 null 先想到 filter 上下文,不是故障。
GET tickets/_search?timeout=500ms # 每分片执行上限 超时返回部分结果 GET tickets/_search?routing=user-8821 # 只查此路由的分片 大客户提速 GET tickets/_search?preference=_local # 优先本节点分片 副本缓存友好 GET tickets/_count?q=status:pending # 只要数不要文档 轻量计数
四个参数各有位置:超时保交互体验;routing 把查询裁剪到相关分片(写入侧也用同一 routing 才成立);本地偏好让重复查询吃到节点缓存;计数接口在仪表盘场景省下文档传输。
背景:运营反馈搜索偶发"结果变少",复现发现恰好在高峰期。操作:抓到异常响应,timed_out 为 true,took 恰等于客户端设置的超时值;看慢查询日志(9.3 的方法),一条聚合重查询挤占了分片线程池。结果:把重报表查询迁到只读副本专用队列并拆小时间范围,超时率归零。解读:两阶段模型下,任一分片超时都会让整体结果不完整——timed_out 是第一个要看的字段,比 took 更重要。变式:无法拆走重查询时,给搜索请求单独设更长的超时并把交互查询与报表查询分到不同索引或不同客户端超时策略,避免互相拖累。
⚠️ 常见坑:把 size 拉到一万一次取全量导数据——两阶段的归并成本与堆内存压力同时爆炸。导出走滚动查询或点后查询(5.3 的主角),别拿搜索接口当导出管道。
💡 关键直觉:搜索是"问分片要排名",不是"问分片要数据"。第一阶段轻装快跑,第二阶段才取重货——理解这一点,分页、路由、超时的行为都能自行推导。
| 考核点 | 达标标准 |
|---|---|
| 请求四件套 | 说出 query、size 与 from、_source 各自管什么 |
| 两阶段分工 | 画出 query 与 fetch 的数据流,标出轻名单与重取回的分界 |
| 深分页病根 | 推导 from 为九百九时每个分片要回多少候选、协调节点归并多少 |
| 响应读序 | 先看 timed_out 再看 took,解释 total 标注 gte 的时机 |
| 参数位置 | 超时、routing、本地偏好各自适用的场景与前提 |
画像参数把一次查询在各阶段的耗时拆成账单:
GET tickets/_search { "profile": true, "query": { "match": { "title": "退款" } } }
响应里的画像分片段按阶段列出耗时:查询段的数字对应第一阶段各分片的执行成本,取回段对应第二阶段搬运 _source 的成本。对比两条查询的账单,"查得多还是搬得多"从直觉变成数字——第 9 章慢查询诊断的分期方法,用的正是这张账单,在这里先认识它。
舞台搭好,下一节请出主角:Query DSL,从 match 的暗号游戏一路讲到 bool 的组合拳。