摘要

本文深入讲解 Elasticsearch 7.3 中查询 DSL 的核心用法,重点拆解 match、match_phrase、query_string、multi_match 等全文检索语句在真实业务中的差异和坑位。通过完整的索引 mapping 配置、样例数据以及 Kibana Dev Tools 请求示例,展示从 match_all 查询所有,到 match 的 OR/AND 控制,再到 match_phrase 的顺序匹配与 slop 容忍度,最后扩展到 query_string 的逻辑表达式、多字段搜索和模糊匹配。


1. 概述

Elasticsearch 提供了基于 JSON 的完整查询 DSL(Domain Specific Language,特定域语言)来定义查询。将查询 DSL 视为查询 AST(抽象语法树),它由两种子句组成:

  • 叶子查询子句:在特定域中寻找特定的值,如 match、term、range 查询
  • 复合查询子句:包装其他叶子查询或复合查询,并用于以逻辑方式组合多个查询(例如 bool 或 dis_max 查询),或更改其行为(如 constant_score 查询)

2. 查询所有(match_all)

示例

POST /wzkicu-index/_search
{
  "query":{
    "match_all": {}
  }
}

返回结果解析

执行后,结果字段说明:

  • took:查询花费时间,单位是毫秒
  • time_out:是否超时
  • _shards:分片信息
  • hits:搜索结果总览对象
  • total:搜索到的总数
  • max_score:所有结果中文档得分的最高分
  • _index:索引库
  • _type:文档类型
  • _id:文档 id
  • _score:文档得分
  • _source:文档的数据源

3. 全文检索(full-text query)

全文搜索能够搜索已分析的文本字段,如电子邮件正文、商品描述,使用索引期间应用于字段的同一分词处理查询字符串。

全文搜索的分类包括:match query、match_phrase query、query_string query、multi_match query 等。


3.1 匹配搜索(match query)

全文查询的标准查询,查询条件比较宽松:

  • 需要指定字段名
  • 输入文本会进行分词,比如 “hello world”,会拆分成 hello 和 world,然后进行匹配
  • 如果字段内容中包含 hello 或者 world,就会被查询出来
  • match 是一个部分匹配的模糊查询

match queries 接收 text/numerics/dates,对它们进行分词分析,再组织成一个 boolean 查询,可通过 operator 指定 bool 组合操作(or、and,默认是 or)。

创建索引

PUT /wzk-property
{
  "settings": {},
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word"
      },
      "images": {
        "type": "keyword"
      },
      "price": {
        "type": "float"
      }
    }
  }
}

添加数据

POST /wzk-property/_doc/
{
  "title": "小米电视4A",
  "images": "https://profile-avatar.csdnimg.cn/xxx.jpg",
  "price": 4288
}

POST /wzk-property/_doc/
{
  "title": "小米手机",
  "images": "https://profile-avatar.csdnimg.cn/xxx.jpg",
  "price": 2699
}

POST /wzk-property/_doc/
{
  "title": "华为手机",
  "images": "https://profile-avatar.csdnimg.cn/xxx.jpg",
  "price": 5699
}

OR 匹配(默认)

POST /wzk-property/_search
{
  "query":{
    "match":{
      "title":"小米电视4A"
    }
  }
}

结果:不仅查到了小米电视、还查询到了小米手机。这是因为 match 默认是 OR 关系,分词后任意一个词命中即算匹配。

AND 匹配

如果需要精确查找,可以使用 and 方式:

POST /wzk-property/_search
{
  "query": {
    "match": {
      "title": {
        "query": "小米电视4A",
        "operator": "and"
      }
    }
  }
}

结果:已经精准匹配到了小米电视4A。


3.2 短语搜索(match_phrase query)

match_query 是分词的,text 也是分词的。match_phrase 的分词结果必须在 text 字段中都包含,而且顺序必须相同,而且必须是连续的。

基本用法

POST /wzk-property/_search
{
  "query": {
    "match_phrase": {
      "title": "小米电视"
    }
  }
}

顺序要求

POST /wzk-property/_search
{
  "query": {
    "match_phrase": {
      "title": "电视小米"
    }
  }
}

由于 “电视小米” 分词后顺序与 “小米电视” 不同,所以没有匹配到结果。

slop 参数(跳词容忍度)

通过 slop 可以跳过一个词来让 match_phrase 匹配到顺序的结果:

POST /wzk-property/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "小米4A",
        "slop": 1
      }
    }
  }
}

3.3 query_string 查询

该查询与 match 类似,但是 match 需要指定字段名,query_string 是在所有字段中搜索,范围更广泛。

Query String Query 提供了无需指定某字段而对文档全文进行匹配查询的一个高级查询,同时可以指定在哪些字段上进行匹配。

广泛查询

POST /wzk-property/_search
{
  "query": {
    "query_string": {
      "query": "2699"
    }
  }
}

指定字段查询

POST /wzk-property/_search
{
  "query": {
    "query_string": {
      "query": "2699",
      "default_field": "title"
    }
  }
}

逻辑查询(OR/AND)

POST /wzk-property/_search
{
  "query": {
    "query_string": {
      "query": "手机 OR 小米",
      "default_field": "title"
    }
  }
}
POST /wzk-property/_search
{
  "query": {
    "query_string": {
      "query": "手机 AND 小米",
      "default_field": "title"
    }
  }
}

模糊查询

使用 ~ 表示模糊匹配,~1 表示允许1个词变动:

POST /wzk-property/_search
{
  "query": {
    "query_string": {
      "query": "小米~1",
      "default_field": "title"
    }
  }
}

多字段支持

POST /lagou-property/_search
{
  "query": {
    "query_string" : {
      "query":"2699",
      "fields": ["title","price"]
    }
  }
}

3.4 多字段匹配查询(multi_match query)

如果需要在多个字段上进行文本搜索,可用 multi_match。multi_match 在 match 的基础上支持对多个字段进行文本查询。

基本用法

POST /wzk-property/_search
{
  "query": {
    "multi_match" : {
      "query":"小米4A",
      "fields": ["title","images"]
    }
  }
}

4. 错误速查

症状根因定位修复
用 match 查询”小米电视4A”,结果把”小米手机”也查出来match 默认 operator=OR,中文分词后任意一个词命中即算匹配在 Kibana 中使用 _analyze 查看 title 分词结果,确认分词粒度在 match 中显式设置 “operator”: “and”,或改用 keyword/精确匹配字段承载商品名
match_phrase 查不到预期文档(如”电视小米""小米4A”均无结果)match_phrase 要求分词顺序与位置连续,默认不允许跳词用 _analyze 查看短语分词顺序,对比 _source.title 的实际分词顺序使用 “slop”: N 放宽位置约束,或改写查询短语与文案保持一致
query_string 报解析错误或查不到数据query_string 语法较复杂,逻辑运算符、特殊字符未转义,或 default_field 不含目标内容查看 Kibana 报错信息,逐步简化 query 字符串,只保留单词验证避免直接透传用户输入,必要时对 + - && || 等字符进行转义
使用 query_string 模糊查询”小米~1”但结果过多或过少模糊匹配基于编辑距离,且受 analyzer 影响,并非”看起来相似就一定命中”对同一单词分别用 _analyze 和 query_string 测试,观察实际命中词条明确业务接受的模糊程度,合理设置 1/2,必要时改为前缀/通配符或拼音索引等更明确方案
multi_match 跨字段查询命中不符合预期多字段中字段类型和分词方式不同,score 被某个字段主导,导致排序或命中偏移查看 mapping 中各字段的 type/analyzer,并用单字段 match 对比效果在 multi_match 中显式配置 fields 权重(如 “title^3”),或统一文本字段的 analyzer,避免 keyword 与 text 混用产生误解
match_all 能查到文档,但任一全文查询都查不到字段被映射为 keyword 或未被索引,全文查询打在错误字段上用 mapping 接口确认字段 type 及 index 属性,检查查询 JSON 中的字段名拼写将字段改为 text 或设置合适的多字段(text + keyword),并校正 DSL 中的字段名,重建索引后再次验证

5. 总结

区分 match、match_phrase、query_string、multi_match 的匹配边界和分词语义,是中文搜索是否”搜得到”的关键。

  • match:分词后任意匹配(OR)或全部匹配(AND)
  • match_phrase:分词顺序连续匹配,支持 slop 跳词
  • query_string:支持逻辑运算符、多字段、模糊查询
  • multi_match:多字段全文搜索,支持字段权重