侧边栏壁纸
博主头像
Setyg的博客

当秋风染红落叶的时候,就是新生~

  • 累计撰写 86 篇文章
  • 累计创建 66 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Elasticsearch 查询 DSL 学习实践

Setyg
2026-09-20 / 0 评论 / 0 点赞 / 4 阅读 / 0 字

Elasticsearch 的查询 DSL(Domain Specific Language)是基于 JSON 的检索语言,所有搜索请求都通过它来描述。掌握 Query DSL 是用好 Elasticsearch 的关键——它决定了检索结果准不准、快不快。本文从基本概念讲起,把最常用的七种查询类型整理成可直接照抄的示例,并补充实际使用中容易踩的坑。

一、基本概念

概念 说明 关系型数据库类比
索引(Index) 文档的集合,是检索的基本单位 表(Table)
文档(Document) 存储在索引中的数据单元,JSON 格式 行(Row)
字段(Field) 文档中的键值对 列(Column)
映射(Mapping) 字段的类型定义,决定该字段能被怎样查询 表结构(Schema)
类型(Type) 7.0 之前一个索引可有多个类型;7.0 起一个索引只能有一个类型 _doc,8.0 已彻底移除该概念 已废弃

检索请求统一发到 _search 接口,一个完整的查询体除了 query,还可以带排序、分页、字段过滤和聚合:

GET /my_index/_search
{
  "query":   { "match": { "title": "elasticsearch" } },
  "_source": ["title", "create_time"],
  "from":    0,
  "size":    10,
  "sort":    [{ "create_time": "desc" }]
}

二、常用查询类型速查

查询类型 用途 是否分词 适用字段
match 全文检索,最常用的查询 是 text
term 精确匹配单个词条 否 keyword / 数值 / 布尔
range 范围查询 否 数值 / 日期 / keyword
bool 逻辑组合多个查询条件 — —
wildcard 通配符匹配(*、?) 否 keyword
query_string Lucene 语法的字符串查询 视写法而定 text
nested 查询嵌套对象内部字段 视内层查询而定 nested 类型字段

三、示例详解

1. Match Query:全文检索

对查询词做分词后再匹配,是文本字段的默认选择。

{
  "query": {
    "match": {
      "field_name": "search_term"
    }
  }
}

常用参数:

{
  "query": {
    "match": {
      "title": {
        "query": "elasticsearch query dsl",
        "operator": "and",
        "minimum_should_match": "2"
      }
    }
  }
}
  • operator:默认 or(分词后任一词条命中即返回),改为 and 则要求全部命中,召回率降低但精确度提高。
  • minimum_should_match:最少命中几个词条,比 and 更灵活,例如 "75%"。

2. Term Query:精确匹配

{
  "query": {
    "term": {
      "field_name": "exact_value"
    }
  }
}

注意:term 不做分词,匹配的是倒排索引里的词条,而不是原始字段值。因此它只应该用在 keyword、数值、布尔、日期这类字段上;对一个 text 字段用 term 查整句话,几乎一定查不到结果。

3. Range Query:范围查询

{
  "query": {
    "range": {
      "timestamp": {
        "gte": "2023-10-01T00:00:00Z",
        "lt": "2023-10-31T23:59:59Z"
      }
    }
  }
}

四个边界参数:gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)。日期字段还支持日期数学表达式:

{
  "query": {
    "range": {
      "create_time": { "gte": "now-7d/d", "lte": "now" }
    }
  }
}

now-7d/d 表示「七天前的零点」,/d 是取整到天,适合做「最近七天」这类需求。

4. Bool Query:组合查询

{
  "query": {
    "bool": {
      "must": [
        { "match": { "field1": "value1" } },
        { "range": { "field2": { "gte": 10, "lte": 20 } } }
      ],
      "should": [
        { "term": { "field3": "value3" } }
      ],
      "must_not": [
        { "term": { "field4": "value4" } }
      ]
    }
  }
}

四个子句的语义与打分行为:

子句 语义 参与打分
must 必须匹配 是
filter 必须匹配 否,可被缓存,过滤条件优先用它
should 可选匹配,命中可加权 是
must_not 必须不匹配 否

两个容易踩的点:

  • 只关心「有没有」而不关心「有多相关」的条件(比如状态、时间范围、租户 ID),放进 filter 而不是 must,可以跳过打分并被缓存,性能更好。
  • should 的命中数量要求取决于上下文:当 bool 里没有 must / filter 时,默认必须命中至少一个 should;一旦同时存在 must / filter,should 默认变成纯加分项,命中 0 个也能返回。需要强制时显式写 "minimum_should_match": 1。

5. Wildcard Query:通配符查询

{
  "query": {
    "wildcard": {
      "field_name": "*pattern*"
    }
  }
}

* 匹配任意多个字符,? 匹配单个字符。也可用对象写法指定参数:

{
  "query": {
    "wildcard": {
      "field_name": {
        "value": "abc*",
        "case_insensitive": true
      }
    }
  }
}

性能提示:通配符匹配的是词典中的词条,以 * 开头(如 *pattern*)无法利用前缀索引,相当于遍历全部词条,字段基数大时会明显变慢。前缀匹配场景优先考虑 prefix 查询或 wildcard 字段类型(7.9+);右侧模糊匹配、需要打字即搜的场景更适合 match_phrase_prefix 或 search_as_you_type。

6. Query String Query:Lucene 语法查询

{
  "query": {
    "query_string": {
      "query": "field1:value1 AND field2:value2"
    }
  }
}

支持 AND / OR / NOT、field:value、括号分组、通配符等 Lucene 语法,适合把用户输入或配置项直接当查询表达式解析。使用时注意:

  • 语法错误会直接抛异常(默认 lenient: false),面向用户输入的场景建议改用语法更宽松、不会报错的 simple_query_string。
  • 不指定字段时会用 default_field,或用 fields 指定多个候选字段。

7. Nested Query:嵌套对象查询

{
  "query": {
    "nested": {
      "path": "address",
      "query": {
        "bool": {
          "must": [
            { "match": { "address.city": "New York" } },
            { "match": { "address.state": "NY" } }
          ]
        }
      }
    }
  }
}

普通对象数组在底层是「扁平化」存储的,address.city 和 address.state 的对应关系会丢失,查「city 是 A 且 state 是 B」可能匹配到并不存在的组合。用 nested 查询可以保持数组内每个对象的独立性,但前提是映射里显式声明了嵌套类型:

PUT /my_index
{
  "mappings": {
    "properties": {
      "address": { "type": "nested" }
    }
  }
}

如果字段没有声明为 nested,执行嵌套查询会直接报 [nested] failed to find nested object under path,而后续再改类型需要重建索引(reindex),所以建模阶段就要想清楚。

四、其他常见坑

  • 分页深度限制:from + size 受 index.max_result_window 限制,默认最多只能翻到第 10000 条。深分页应改用 search_after 或滚动查询(scroll / PIT)。
  • text 与 keyword 双字段:字符串字段动态映射后会同时生成 text(分词,供全文检索)和 keyword 子字段(不分词,供排序、聚合、精确匹配),写查询时容易搞混,注意区分 field 与 field.keyword。
  • 排序和聚合不能用 text 字段:对 text 字段做排序或 terms 聚合会报 Fielddata is disabled,应该用它的 .keyword 子字段。
  • 先看映射再写查询:用 GET /my_index/_mapping 确认字段类型,能避免大部分「查不到结果」的问题。

五、速查卡

// 全文检索
{ "match": { "title": "关键词" } }

// 精确匹配(keyword 字段)
{ "term": { "status": "ACTIVE" } }

// 范围
{ "range": { "price": { "gte": 10, "lte": 20 } } }

// 组合:must 打分 + filter 过滤 + should 加分 + must_not 排除
{ "bool": {
    "must":     [ ... ],
    "filter":   [ ... ],
    "should":   [ ... ],
    "must_not": [ ... ]
} }

// 通配符
{ "wildcard": { "name": "abc*" } }

// Lucene 语法
{ "query_string": { "query": "field1:v1 AND field2:v2" } }

// 嵌套对象
{ "nested": { "path": "address", "query": { ... } } }
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区