Elasticsearch的match查询

26 阅读4分钟

Match:不简单的搜索

如果你用过 Elasticsearch,肯定写过这样的查询:

{
  "query": {
    "match": {
      "title": "最新手机发布"
    }
  }
}

看起来简单,对不对?但我想告诉你,这个看似简单的 match 查询,可能是你用得最不到位的功能。

它真不是字符串匹配

很多人以为 match 就是个字符串匹配——你给它什么词,它就找什么词。其实完全不是那么回事。

让我问你:当你搜索“最新手机发布”时,你希望找到什么?

  • 包含“最新手机发布”这句话的文章?
  • 包含“最新”、“手机”、“发布”这些词的文章?
  • 或者“新款手机上市”这样的同义内容?

match 默认做的是第二件事。它会把你输入的文本拆开、分析、然后去找。这就引出了第一个关键点:分析器决定了搜索结果

分析器:幕后玩家

你的搜索词怎么被拆分,取决于字段的分析器。如果 title 字段用的是 standard 分析器:

  • “最新手机发布” → “最新”、“手机”、“发布”

如果用 ik_smart

  • “最新手机发布” → “最新”、“手机发布”

看出来了么?不同的分析器,搜索结果天差地别。我吃过这个亏:有一次搜索“机器学习”,就是查不到相关文档,折腾半天才发现,字段用的是 standard 分析器,把“机器学习”拆成了“机”、“器”、“学”、“习”四个单字……

所以,写 match 查询前,先搞清楚你的字段怎么分析文本:

GET your_index/_mapping

几个实际场景

场景一:搜商品

{
  "query": {
    "match": {
      "product_name": {
        "query": "华为Mate 60 Pro手机",
        "operator": "and"
      }
    }
  }
}

注意这里的 "operator": "and"。意思是:必须同时包含“华为”、“Mate”、“60”、“Pro”、“手机”这些词。这样搜出来的结果才精准。

要是默认的 or 呢?可能“华为手机”、“小米Pro 60”都出来了——完全不是你要的。

场景二:搜文章

文章内容搜索可以松一点:

{
  "query": {
    "match": {
      "content": "Python数据分析教程入门"
    }
  }
}

这里用默认的 or 挺好,因为用户可能记不全,只要匹配部分关键词就是相关文章。

场景三:模糊搜索

用户拼写错了怎么办?

{
  "query": {
    "match": {
      "description": {
        "query": "elasticserch",
        "fuzziness": "AUTO"
      }
    }
  }
}

fuzziness: "AUTO" 会让 Elasticsearch 自动判断允许几个字符的拼写错误。这是个贴心功能,但别滥用——模糊匹配很耗性能。

那些容易踩的坑

1. 中文搜索的坑

如果你没配置中文分词器,中文搜索基本不可用。要么每个字单独搜,要么整个句子当做一个词搜。解决方案很简单:用 IK 分词器。

2. 数字搜索的怪现象

搜索“iPhone 14”,结果“iPhone 13”、“iPhone 15”都出来了?因为数字被当成字符串了。如果你的商品型号包含数字,考虑用 keyword 类型存一份。

3. 停用词问题

搜索“to be or not to be”,可能搜不到想要的结果,因为“to”、“be”、“or”、“not”这些词太常见,被当成停用词过滤掉了。这时候要用 match_phrase

match_phrase:当顺序重要时

{
  "query": {
    "match_phrase": {
      "content": "机器学习算法"
    }
  }
}

match_phrase 要求词的顺序必须一致,中间可以插入其他词(通过 slop 参数控制间隔距离)。

但注意:match_phrase 对性能影响较大,尤其是在大文本字段上。

性能小贴士

  1. 别在大字段上用 match:如果非要在几万字的长文章里搜索,考虑提取摘要单独建字段。

  2. minimum_should_match 控制召回率

    {
      "match": {
        "content": {
          "query": "前端开发工程师面试指南",
          "minimum_should_match": "75%"
        }
      }
    }
    

    至少匹配75%的词,既保证相关性,又控制结果数量。

  3. 避免不必要的模糊搜索:只在用户明确需要的场景用 fuzziness

什么时候不用 match?

match 虽好,但不是万能的:

  • 精确匹配用 term:比如状态值、标签
  • 通配符搜索用 wildcard:比如文件路径匹配
  • 正则表达式用 regexp

最后说点实在的

我见过太多项目把 Elasticsearch 当数据库用,所有搜索都用 match,然后抱怨性能差、结果不准。其实 Elasticsearch 的查询 DSL 是个工具箱,match 只是其中最常用的一把螺丝刀。

用对工具的关键是理解:

  • 你的数据是怎么存进去的(映射和分析器)
  • 用户真正想搜什么(查询意图)
  • 你愿意在性能和精度之间怎么权衡(查询参数)

下次写 match 查询时,多想几秒钟。这几个参数调好了,用户体验可能就是天壤之别。


最让我头疼的其实是测试。同一个 match 查询,在测试环境好好的,上了生产就不对劲。后来发现,测试数据量太小,分词效果完全不同。所以,如果你调不好 match 查询,先看看测试数据是不是太“干净”了。

真实世界的搜索,往往比你想的要混乱。