前言
Query DSL(Domain Specific Language,领域专用语言)是 Elasticsearch 官方标准检索语法,依托 JSON 结构实现全文检索、结构化筛选、自定义打分等。
ES 的 Query DSL 整体分为 叶子查询子句(Leaf Query)与 复合查询子句(Compound Query) 两大体系:叶子查询是最小查询单元,负责单一条件匹配;复合查询用于嵌套组合多个子查询,实现多条件拼接、权重调整、自定义排序等复杂业务逻辑。
一、Query 上下文 vs Filter 上下文
ES 所有查询子句的执行逻辑由所处上下文决定,区分二者是查询优化的重中之重。
| 维度 | Query 上下文 | Filter 上下文 |
|---|---|---|
| 核心逻辑 | 计算文档相关性分数_score,分值越高排序越靠前 |
二元判定:文档匹配 / 不匹配,不计算打分 |
| 适用场景 | 全文模糊检索、需要相关性排序(match/multi_match) | 精确过滤、范围筛选(状态、日期、数字区间) |
| 缓存机制 | 无缓存,每次检索重新计算得分 | 结果自动缓存(bitset 位图),高频查询大幅提速 |
| 出现位置 | 顶层query、bool.must、bool.should |
bool.filter、bool.must_not、constant_score.filter |
开发规范:能用 filter 绝不使用 query做精准过滤,减少不必要打分计算,优化检索 QPS。
二、叶子查询子句
叶子查询无法嵌套子查询,分为 全文检索(Full text)和 精准 Term 级检索(Term-level) 两大分支,分别适配text分词字段、keyword 基础类型字段。
2.1 全文检索
查询输入内容会经过字段绑定的分析器分词,再倒排索引匹配,用于模糊搜索、关键词检索。
可用关键字清单:intervals、match、match_bool_prefix、match_phrase、match_phrase_prefix、multi_match、query_string、simple_query_string
示例:基础 match 分词查询
对 message 字段分词后匹配关键词this is a test,自动计算相关性得分
json
GET _search
{
"query": {
"match": {
"message": {
"query": "this is a test"
}
}
}
}
multi_match可一次性在多个字段(title/desc)搜索同一关键词,是多字段检索首选。
2.2 Term 级精准查询
不会对搜索词分词 ,完全精确匹配原始词条,多用于枚举、ID、日期、数值筛选。
可用关键字清单:exists、fuzzy、ids、prefix、range、regexp、term、terms、terms_set、wildcard
示例 1:term 精确匹配
keyword 字段专用
json
GET my_index_search?pretty
{
"query": {
"term": {
"full_text": "Quick Brown Foxes!"
}
}
}
示例 2:range 区间筛选
数值 / 日期通用,boost 提升权重
筛选 age 在 10~20 之间的文档,boost=2 提升本条条件打分权重
json
GET _search
{
"query": {
"range": {
"age": {
"gte": 10,
"lte": 20,
"boost": 2
}
}
}
}
三、复合查询子句
多条件组合与自定义打分
复合查询可嵌套任意叶子 / 复合查询,ES 主流包含bool、boosting、constant_score、dis_max、function_score五种,覆盖绝大多数复杂检索场景。
3.1 Bool Query
布尔查询,最常用
由must/filter/should/must_not4 个子句组成,实现 SQL 的 AND/OR/NOT 逻辑,是多条件拼接的核心语法。
| 子句 | 逻辑含义 | 是否算分 | 等价 SQL |
|---|---|---|---|
| must | 必须全部满足 | ✅ 参与打分 | AND |
| filter | 必须全部满足 | ❌ 无打分、可缓存 | AND(性能优选) |
| should | 可选匹配,配合 minimum_should_match 控制命中数 | ✅ 参与打分 | OR |
| must_not | 必须不满足 | ❌ 无打分 | NOT |
示例:多条件组合查询
用户 = kimchy、标签 = tech、年龄不在 10~20 区间,标签匹配 wow 或 elasticsearch(至少命中 1 个)
json
POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
bool 无 must/filter 时,should 默认至少匹配 1 项;存在 must/filter 时 should 默认不强制匹配,需手动配置 minimum_should_match。
3.2 Boosting Query
保留命中文档,但对匹配负面条件的数据降低排序分数,不直接过滤数据。
-
positive:正向条件(必须匹配,正常算分)
-
negative:负面条件(匹配后分数 ×negative_boost,权重降低)
-
negative_boost:降级系数(0~1 之间,越小降级越明显)
示例:搜索 apple,命中 pie 相关内容的文档降权
json
GET _search
{
"query": {
"boosting": {
"positive": {
"term": {
"text": "apple"
}
},
"negative": {
"term": {
"text": "pie tart fruit crumble tree"
}
},
"negative_boost": 0.5
}
}
}
3.3 Constant_score
固定分值查询,忽略原始 BM25 打分,所有命中 filter 条件的文档统一设置固定 boost 分数,适合不需要相关性排序、只做筛选的场景。
json
GET _search
{
"query": {
"constant_score": {
"filter": {
"term": {
"user": "kimchy"
}
},
"boost": 1.2
}
}
}
3.4 Dis_max
最佳字段匹配查询
多字段检索时,取单字段最高得分作为文档总分,不叠加多字段分数,避免多字段命中导致分数虚高,常用于标题 + 正文双字段搜索。
-
queries:多组查询条件
-
tie_breaker:次要匹配项权重系数(0~1)
json
GET _search
{
"query": {
"dis_max": {
"queries": [
{
"term": {
"title": "Quick pets"
}
},
{
"term": {
"body": "Quick pets"
}
}
],
"tie_breaker": 0.7
}
}
}
3.5 Function_score
在原始查询得分基础上,通过内置函数自定义调整文档权重,实现按热度、销量、发布时间、随机排序等个性化需求。
常用函数:random_score 随机打分、field_value_factor 基于字段值加权、weight 固定权重。
示例:全量文档随机加权排序,原始分数 ×5
json
GET _search
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"boost": "5",
"random_score": {},
"boost_mode": "multiply"
}
}
}
场景:文章按阅读量加权排序。