连载中 7/20

查询入门:match、term、filter 与 bool

2026-08-13 · 1047 阅读 · 0 评论 · 0 赞

搜索框背后的四个动词

文档能搜到了,老王的搜索框需求也开始膨胀:关键词搜是基本盘,还要按分类筛选、排除下架商品、按价格区间过滤。这些需求在 ES 里对应四个查询动词的分工:match 管全文,term 管精确,match_phrase 管短语,bool 管组合。分清它们,查询就入门了一半。

match:走分词的全文搜索

match 是全文搜索的默认选择,对 text 字段使用。它会先用搜索分词器把输入切成词条,再逐个去倒排里查:

GET /product/_search
{
  "query": {
    "match": { "name": { "query": "燕麦拿铁", "operator": "and" } }
  }
}

搜「燕麦拿铁」被切成「燕麦」「拿铁」两个词条。默认 operator 是 or,命中任意一个词条的文档都返回——召回大,噪声也大;改成 and,两个词条都得命中,精确但召回降。中间态用 minimum_should_match 调节,比如要求至少命中百分之七十五。一个 match 控制不好,搜索结果就在「什么都搜到」和「什么都搜不到」之间反复横跳,运营天天找你聊天。

term:不分词的精确匹配

term 不分词,拿输入整串直接去倒排里找完全相等的词条。所以它配合 keyword 字段用才对:查状态、查品牌、查标签:

{ "term": { "brand.keyword": "503咖啡馆" } }
{ "term": { "status": 1 } }

新手第一坑来了:对 text 字段用 term 查整句。搜 term name 等于「燕麦拿铁」,结果为零——不是数据丢了,是 text 字段的倒排里根本没有「燕麦拿铁」这个完整词条,只有「燕麦」「拿铁」这些切好的碎片。term 找的是词条,不是原文。记住这句:term 的世界里,text 字段存的是碎片,keyword 字段存的才是整串。

match_phrase:要挨着才给过

match 切完词各查各的,「拿铁 新品」四个字分开命中就返回,语序全乱。match_phrase 要求词条按顺序紧挨着出现——底层靠倒排里的位置信息(position)校验。短语搜索精准度高,但召回低,常配 slop 参数放宽一点距离:slop 为 1 表示允许中间隔一个词。「燕麦 拿铁」这种用户整句输入,phrase 是更合适的选择。

query 与 filter:算不算分是分水岭

同样的条件,放在 query 上下文和 filter 上下文里,行为不一样:

上下文算分缓存适用
query算 _score不复用相关性搜索
filter不算位图缓存可复用筛选过滤条件

「是不是上架状态」「价格在不在区间」这类只有是与非的条件,算分毫无意义,白花计算还影响排序——放进 filter,不算分、走缓存,又快又稳。经验法则一句话:决定相关性的进 query,决定在不在的进 filter。

bool:把四个动词组起来

真实搜索从来都是多条件,bool 查询就是组合器,四个槽位对应四种逻辑:

GET /product/_search
{
  "query": {
    "bool": {
      "must":     [ { "match": { "name": "燕麦拿铁" } } ],
      "must_not": [ { "term":  { "status": 0 } } ],
      "filter":   [ { "term":  { "category_id": 7 } },
                    { "range":  { "price": { "gte": 10, "lte": 50 } } } ],
      "should":   [ { "term":  { "tags.keyword": "新品" } } ]
    }
  }
}

must 是算分的与,must_not 是非(天然属于 filter 上下文,不算分),filter 是不算分的与,should 是算分的或。组合语义要记牢一条:有 must 或 filter 时,should 默认变成加分项而非必须项——上面的查询里,「新品」标签的文档会排更前,但不带标签的也能返回;要让 should 变硬性要求,得显式设 minimum_should_match。

小结

四个动词一句话:match 分词全文搜,term 精确打词条,phrase 管语序,bool 做组合。两个心法:对 text 用 term 是第一坑;能用 filter 的都进 filter。把这两个原则刻进肌肉记忆,查询代码就稳了。

查询能跑了,但结果的排序老王不满意度很高:爆款「燕麦拿铁」排在冷门「燕麦酥」后面。排序背后的 _score 是怎么算的?下一篇讲评分:BM25 的直觉与 function_score 的业务加权。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#Elasticsearch#match#term#filter#bool

评论 (0)

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10101 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9873 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9294 阅读 · 21 评论 · 287 赞