深入学习 ElasticSearch 的搜索(三):match_phrase 查询

match_phrase 是 ElasticSearch 中常用的短语查询。

它和 match 很像,都会分析查询文本,但 match_phrase 更严格。

它不只是要求 term 命中,还要求这些 term 在字段中的顺序和位置关系符合短语要求。

简单说:

match 关注“有没有这些词”,match_phrase 关注“这些词是不是按顺序靠在一起”。


一、基本写法

查询正文中包含短语 倒排索引 的文章:

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "content": "倒排索引"
    }
  }
}

match_phrase 适合查:

  • 固定短语
  • 连续词组
  • 标题中的完整表达
  • 需要顺序关系的文本

二、match_phrase 的执行过程

假设查询:

ElasticSearch 搜索

执行过程大致是:

  1. 查询文本经过 analyzer
  2. 得到多个 term
  3. 去倒排索引中找包含这些 term 的文档
  4. 再检查这些 term 的 position
  5. position 符合短语关系才算命中

所以 match_phrase 依赖倒排索引中的 position 信息。

如果字段没有保存位置信息,就无法正常支持短语匹配。


三、和 match 的区别

假设文档内容是:

ElasticSearch 的倒排索引是搜索能力的基础

查询:

{
  "match": {
    "content": "倒排索引 搜索"
  }
}

match 可能命中,因为文档中有:

  • 倒排
  • 索引
  • 搜索

但如果使用:

{
  "match_phrase": {
    "content": "倒排索引 搜索"
  }
}

就不一定命中,因为“倒排索引”和“搜索”之间隔了其他词。

这就是二者差异:

  • match:词命中即可,比较宽松
  • match_phrase:词要按顺序,并且位置关系要符合要求

四、slop:允许词之间有距离

match_phrase 默认要求 term 的位置比较严格。

如果希望中间允许间隔,可以使用 slop

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "content": {
        "query": "倒排索引 搜索",
        "slop": 3
      }
    }
  }
}

slop 可以理解成短语匹配时允许的移动距离。

它适合这种场景:

  • 用户输入的是一个大概短语
  • 文档中这些词不是完全连续
  • 但词之间距离很近,也应该算相关

不过 slop 不宜设置过大,否则 match_phrase 会逐渐失去短语查询的意义。


五、对象写法:slop、analyzer、boost

match_phrase 有两种常见写法。

简写:

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "content": "倒排索引"
    }
  }
}

完整对象写法:

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "content": {
        "query": "倒排索引",
        "slop": 1,
        "boost": 2
      }
    }
  }
}

当只传查询文本时,简写更清楚。

当需要配置 slopanalyzerboost 等参数时,就必须使用对象写法。


六、match_phrase_prefix:短语前缀查询

match_phrase_prefix 可以理解成短语查询的前缀版本。

例如:

POST article_search/_search
{
  "query": {
    "match_phrase_prefix": {
      "title": "ElasticSearch m"
    }
  }
}

它会把最后一个 term 当成前缀处理,适合简单的输入联想。

但如果要做正式的搜索建议,不应该只依赖它,还可以考虑:

  • search_as_you_type
  • completion suggester
  • edge_ngram

七、中文场景要注意分词

中文里使用 match_phrase 时,分词结果尤其重要。

例如查询:

倒排索引

如果 analyzer 结果是:

倒排 / 索引

那么 match_phrase 会检查 倒排索引 是否按顺序相邻。

如果 analyzer 结果是:

倒 / 排 / 索 / 引

那么短语匹配的粒度就变成单字级别,可能带来更多误匹配。

所以排查时先看:

POST article_search/_analyze
{
  "field": "content",
  "text": "倒排索引"
}

只有 analyzer 结果合理,match_phrase 才能合理。


八、中文人名不一定适合只靠 match_phrase

如果搜索的是中文人名,例如:

张三

match_phrase 的效果高度依赖分词器。

如果分词器把它识别成:

张三

那短语查询比较自然。

如果分词器把它拆成:

张 / 三

查询语义就会退化成相邻 token 匹配,误命中风险会上升。

如果“人名”本身是业务对象,更稳的做法是单独建一个实体字段:

{
  "chunk_text": "饭后,张三看着李四,没有说话。",
  "entity_names": ["张三", "李四"]
}

其中:

  • chunk_texttext 做正文全文搜索
  • entity_nameskeyword 数组做人名精确检索

查询人名时用:

POST article_search/_search
{
  "query": {
    "term": {
      "entity_names": "张三"
    }
  }
}

这比只靠正文分词更稳定。


九、match_phrase 适合什么场景

适合:

  • 搜完整标题
  • 搜固定短语
  • 搜日志中的连续片段
  • 搜文章里的明确表达
  • 提高搜索结果精确度

例如:

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "title": "ElasticSearch 入门教程"
    }
  }
}

这比普通 match 更强调标题中是否出现了这个连续表达。


十、不适合什么场景

不适合:

  • 用户随便输入多个关键词
  • 希望尽量多召回结果
  • 字段分词质量不稳定
  • 只想查分类、状态、ID

如果用户输入的是:

ElasticSearch 安装 查询 倒排索引

这更像关键词搜索,通常应该先用 match,再考虑通过 bool 或评分策略优化。


十一、常见误区

1. match_phrase 不是完全等于原文包含

match_phrase 仍然会先分析查询文本。

所以它匹配的是分析后的 term 位置关系,不是直接做原始字符串匹配。


2. 查不到不一定是文档没有

如果 match_phrase 查不到,可能原因包括:

  • analyzer 分词结果不符合预期
  • 查询词顺序和文档中顺序不同
  • 两个词之间距离超过了默认要求
  • 字段没有合适的 position 信息

3. slop 不是越大越好

slop 越大,匹配越宽松,但结果也可能越不精确。

短语查询的价值就在于位置约束。

如果 slop 设置得太大,可能不如直接使用 match


十二、一句话总结

match_phrase 适合查询连续短语。

它和 match 的核心区别是:

match 主要看 term 是否命中,match_phrase 还要看 term 的顺序和位置。

如果要查“固定表达”“连续标题”“短语片段”,优先考虑 match_phrase


参考链接

在这里插入图片描述

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐