全文搜索,用字段分析器分析 query 串,任一 token 命中即可,按 BM25 打分。搜 text 字段的默认选择。
例子 GET /products/_search {"query":{"match":{"description":"wireless headphones"}}} GET /_search {"query":{"match":{"description":{"query":"wireless headphones","operator":"and","minimum_should_match":"75%"}}}} 短语查询,token 必须按顺序连着出现(或允许 slop 个间隔)。做"完整短语"搜索;slop=2 允许中间夹几个词。
例子 {"query":{"match_phrase":{"description":"wireless noise cancelling"}}} {"query":{"match_phrase":{"description":{"query":"wireless headphones","slop":2}}}} 同一个 query 串同时打多个字段,可加权。type=best_fields 取打分最高字段;cross_fields 当成一个大字段。
例子 {"query":{"multi_match":{"query":"wireless","fields":["name^3","description"],"type":"best_fields"}}} 精确值查询,不分词。用于 keyword / 数值 / 布尔 / 日期 字段。对 text 字段用 term 搜 "Apple" 会全空,因为 text 入库时变成了小写。
⚠ 常见坑: term 对 text 字段几乎永远 0 命中,text 入库时小写化 + 分词,"Apple" 变成 "apple"。要么查 name.keyword,要么改用 match。
例子 {"query":{"term":{"status":"active"}}} {"query":{"term":{"name.keyword":"Apple"}}} 字段值等于列表中任意一个就命中,ES 版的 SQL IN。默认上限 65536 个 term,真要更多就调 index.max_terms_count。
例子 {"query":{"terms":{"status":["active","pending","review"]}}} 数值 / 日期 / IP 范围查询。日期支持 date math,now-1d, now/d(向下取整到天), now+5m 等。包含 gte/lte,不含 gt/lt。
例子 {"query":{"range":{"price":{"gte":10,"lte":100}}}} {"query":{"range":{"@timestamp":{"gte":"now-7d/d","lt":"now/d"}}}} bool (must / should / must_not / filter)复制
布尔组合。must = AND(打分), should = OR(打分,影响分数), must_not = NOT(不打分), filter = AND(不打分,可缓存,最快)。不需要打分一律用 filter。
⚠ 常见坑: 把等值 / 范围条件放 must 而不是 filter,既浪费打分 CPU 又错过 filter 缓存。"是不是真"的条件全挪到 filter,"打分排序"的才放 must。
例子 {"query":{"bool":{"must":[{"match":{"description":"wireless"}}],"filter":[{"term":{"in_stock":true}},{"range":{"price":{"lte":200}}}],"must_not":[{"term":{"discontinued":true}}]}}} 通配符匹配,* 任意多字符,? 单字符。跑在 keyword 上(text 上有坑)。前导通配符("*foo")会全索引扫,大索引上很慢。
⚠ 常见坑: 前导通配符("*foo*")是最慢的 query,用不上倒排索引。要 "contains" 搜索,改用 wildcard 字段(7.9+)或 ngram 分析器。
例子 {"query":{"wildcard":{"sku.keyword":{"value":"SKU-*-RED"}}}} keyword 字段上的正则匹配。用 Lucene 风格的 regex(不是完整 PCRE)。整个 term 锚定,不用写 ^$。
⚠ 常见坑: 长 term 上 regex 可能指数级慢;用 max_determinized_states 封顶。高基数字段上 ngram 分析器比 regex 快。
例子 {"query":{"regexp":{"sku.keyword":{"value":"[A-Z]{3}-[0-9]{4}","max_determinized_states":10000}}}} 前缀匹配,找以指定字符串开头的 term。在 keyword 字段上便宜(倒排索引有序)。做"输入即搜"用这个,别用 wildcard。
例子 {"query":{"prefix":{"name.keyword":{"value":"Apple"}}}} Levenshtein 距离模糊匹配,容错拼写。AUTO 按 term 长度选 0/1/2 次编辑。长 term 上慢,用 prefix_length 和 max_expansions 封顶。
例子 {"query":{"fuzzy":{"name":{"value":"helo","fuzziness":"AUTO","prefix_length":1}}}} 匹配字段存在(非 null、非空)的文档。ES 里最接近 SQL IS NOT NULL 的写法。放 must_not 里即 IS NULL。
例子 {"query":{"exists":{"field":"email"}}} {"query":{"bool":{"must_not":[{"exists":{"field":"email"}}]}}} 在一次 query 里按 id 拉一小批文档。比 _mget 灵活(同一 query 接口,可打分、可高亮)。
例子 {"query":{"ids":{"values":["1","2","42"]}}} nested 字段内的查询,"所有条件落在同一个 nested 对象上"必用。inner_hits 返回究竟是哪个 nested 元素命中。
例子 {"query":{"nested":{"path":"variants","query":{"bool":{"must":[{"term":{"variants.color":"red"}},{"range":{"variants.price":{"lte":50}}}]}},"inner_hits":{}}}} 匹配离某点 D 距离内的文档。配 sort:_geo_distance 实现"最近优先"。默认距离单位米,支持 km、mi。
例子 {"query":{"geo_distance":{"distance":"5km","location":{"lat":40.71,"lon":-74.0}}}} 自定义打分,按时间衰减、热度、地理距离、随机、脚本来改 BM25 分。score_mode 和 boost_mode 控制怎么混。
例子 {"query":{"function_score":{"query":{"match":{"description":"wireless"}},"functions":[{"gauss":{"@timestamp":{"origin":"now","scale":"30d"}}}],"boost_mode":"multiply"}}} 每条命中返回带 <em>...</em> 标记的片段(可配置)。三种 highlighter:unified(默认,均衡), plain(慢但准), fvh(快,需要 term_vector=with_positions_offsets)。
例子 {"query":{"match":{"description":"wireless"}},"highlight":{"fields":{"description":{"fragment_size":150,"number_of_fragments":3}}}} search_after (deep pagination)复制
稳定深度分页,把上一页最后一条的 sort 值作为下一页的 search_after。翻 10000 之外的页用这个,别用 from + size。
⚠ 常见坑: from + size 深翻页默认到 index.max_result_window=10000 就报错,而且即使没到,每个 coordinator 也要从每个 shard 拉 from+size 条。用 search_after 或 PIT。
例子 {"size":20,"sort":[{"@timestamp":"desc"},{"_id":"asc"}],"search_after":["2026-05-26T10:00:00Z","abc123"]} scroll = 离线导出用的老快照接口。PIT(point-in-time, 7.10+)= 现代替代品,配 search_after 实现可恢复 + 快照一致的分页。
例子 POST /products/_pit?keep_alive=5m GET /_search {"pit":{"id":"<pit-id>","keep_alive":"5m"},"size":100,"sort":[{"_shard_doc":"asc"}]} match_all 返回所有文档,分数恒为 1,是默认 query,也是"给我全部"(分页)的正路。match_none 什么都不返回,在模板化 query 里当占位符好用。
例子 {"query":{"match_all":{}}} {"query":{"match_none":{}}} terms_set,当命中的 term 数达到下限就匹配,下限来自字段或脚本,"至少列出 N 个技能就算匹配"。表达"5 选 3"这类需求的 DSL 写法。
例子 {"query":{"terms_set":{"skills":{"terms":["es","sql","python"],"minimum_should_match_field":"required_matches"}}}} constant_score 包住一个 filter,让所有命中拿同一固定分(boost),完全跳过 BM25。想要 filter 缓存的速度,又需要某个 should 子句贡献一个平的加分时用它。
例子 {"query":{"constant_score":{"filter":{"term":{"in_stock":true}},"boost":1.2}}} dis_max,跑多个 query,取打分最高的那个作为结果分(再加 tie_breaker × 其余)。避免同一 term 命中多个字段时文档被重复加分。
例子 {"query":{"dis_max":{"queries":[{"match":{"title":"wireless"}},{"match":{"body":"wireless"}}],"tie_breaker":0.3}}} query_string · simple_query_string复制
把 Lucene 语法串("wireless AND (headphones OR earbuds) -wired")解析成 query。query_string 强但语法错会抛异常;simple_query_string 永不报错,适合直接接终端用户输入。
⚠ 常见坑: query_string 绝不要直接暴露给不可信用户,畸形或恶意 query(深通配、巨大布尔树)会报错或拖垮集群。公开搜索框用 simple_query_string。
例子 {"query":{"simple_query_string":{"query":"wireless +headphones -wired","fields":["name^2","description"]}}} more_like_this,基于共有的显著 term,找与给定文本或种子文档相似的文档。不用 embedding 就能做经典的"相关文章" / "类似商品"。
例子 {"query":{"more_like_this":{"fields":["title","body"],"like":[{"_index":"articles","_id":"42"}],"min_term_freq":1,"max_query_terms":12}}} knn 检索,在 dense_vector 字段上用 HNSW 做近似最近邻(8.x 顶层 knn)。返回离查询向量最近的 k 个,是语义 / RAG 检索的召回那一半。配 filter 限定候选集。
例子 POST /docs/_search {"knn":{"field":"embedding","query_vector":[0.12,0.83],"k":10,"num_candidates":100,"filter":{"term":{"lang":"zh"}}}} distance_feature,按 date 或 geo_point 字段离某 origin 的远近加分,随距离衰减,在 bool 里便宜地把更新 / 更近的结果往上提。比 function_score 做常见的"时效 / 就近"加分更快。
例子 {"query":{"bool":{"must":{"match":{"description":"coffee"}},"should":{"distance_feature":{"field":"@timestamp","origin":"now","pivot":"7d"}}}}} sort (multi-field, missing, mode)复制
按一个或多个字段排序,各自 asc/desc,用 missing:_first/_last 处理空值,用 mode(min/max/avg/sum/median)把数组字段折叠成一个值。按字段排序会关掉算分,除非显式加 track_scores。
例子 {"sort":[{"price":{"order":"asc","missing":"_last"}},{"_score":"desc"}]} {"sort":[{"ratings":{"order":"desc","mode":"avg"}}]} _source filtering · stored_fields复制
控制每条命中返回什么,_source:false 完全不返回 body,_source:{includes,excludes} 挑字段,fields:[...] 返回格式化后的值(适合 runtime field 和日期)。给宽文档瘦身。
例子 {"_source":{"includes":["name","price"]},"query":{"match_all":{}}} {"_source":false,"fields":["name","@timestamp"],"query":{"match_all":{}}} 用运行时参数跑一个存好的 Mustache 搜索模板,query 结构留在服务端,客户端只传值。比用字符串拼 query JSON 更干净也更安全。
例子 POST /_scripts/find_by_status {"script":{"lang":"mustache","source":{"query":{"term":{"status":"{{s}}"}}}}} GET /products/_search/template {"id":"find_by_status","params":{"s":"active"}} GET /_search?profile=true复制
profile 一个 query,拿到逐 shard、逐组件的耗时拆解(哪个子查询、rewrite、collector)。排除 mapping 错误后,定位"这个搜索为什么慢"的权威工具。
例子 GET /products/_search {"profile":true,"query":{"bool":{"must":[{"match":{"description":"wireless"}}]}}}