← 返回题目列表

Elasticsearch 中 query 和 filter 有什么区别?

高频 中等 第 16 / 30 题 更新于 2026/07/28
ElasticsearchQuery DSLfilter相关性评分

简化版

query context 会判断文档是否匹配,并计算 _score 相关性分数;filter context 只判断是否匹配,不计算相关性,适合状态、时间范围、权限、分类这类精确过滤条件。面试里可以概括为:query 负责“有多相关”,filter 负责“要不要这条”。

详细版

Elasticsearch Query DSL 里,同一个条件放在不同上下文中,语义和性能特点不同。

query context:

  • 需要计算 _score
  • 适合全文检索和相关性排序;
  • 常见查询:matchmulti_matchmatch_phrase
  • 例如搜索“Java 集合”,希望更相关的文章排前面。

filter context:

  • 只返回 true/false;
  • 不计算相关性分数;
  • 适合精确过滤;
  • 经常可以被缓存;
  • 常见条件:状态、租户、权限、时间范围、枚举值。

典型写法是 bool 查询:

GET /articles/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "Java 集合" } }
      ],
      "filter": [
        { "term": { "status": "published" } },
        { "range": { "created_at": { "gte": "now-30d" } } }
      ]
    }
  }
}

这里 title 用 query 参与评分,statuscreated_at 用 filter 缩小范围。

完整版教学

一、为什么要区分 query 和 filter

搜索系统里有两类问题:

第一类是“这篇文章和关键词有多相关”:

用户搜:Java 并发
文章 A:Java 并发编程面试题
文章 B:Java 基础知识

这种问题需要评分,文章 A 应该排在前面。

第二类是“这篇文章是否满足硬条件”:

status = published
tenant_id = 1001
created_at >= now-30d

这种条件没有“更相关”的概念,只需要判断能不能进入结果集。把两类问题分开,查询语义会更清晰,性能也更容易优化。

二、query context 关注相关性

query context 会计算 _score。例如:

{
  "query": {
    "match": {
      "content": "Elasticsearch 倒排索引"
    }
  }
}

这里 match 查询会分析用户输入,匹配倒排索引,并根据相关性算法计算每个文档的 _score。默认情况下,搜索结果会按 _score 从高到低排序。

query context 适合:

  • 搜索标题、正文、评论;
  • 多字段权重匹配;
  • 短语匹配;
  • 需要用户感知“排序更准确”的场景。

三、filter context 关注硬过滤

filter context 不计算 _score,只判断是否匹配。典型写法:

{
  "query": {
    "bool": {
      "filter": [
        { "term": { "category": "java" } },
        { "range": { "price": { "lte": 100 } } }
      ]
    }
  }
}

这些条件不需要排名:

  • 分类等于 Java;
  • 价格小于 100;
  • 是否已发布;
  • 用户是否有权限看;
  • 时间是否在最近 7 天。

把它们放到 filter 中,可以避免无意义评分,也让 Elasticsearch 有机会复用过滤结果。

四、bool 查询里各子句怎么理解

bool 查询是面试最高频入口之一:

子句语义是否影响评分
must必须匹配通常影响
should可选匹配,可提升相关性通常影响
filter必须匹配不影响
must_not必须不匹配不影响

例如电商搜索:

{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "无线耳机" } }
      ],
      "filter": [
        { "term": { "brand": "sony" } },
        { "range": { "price": { "gte": 300, "lte": 1500 } } }
      ],
      "must_not": [
        { "term": { "status": "deleted" } }
      ]
    }
  }
}

用户搜索词走 must,品牌和价格走 filter,已删除商品走 must_not

五、常见错误

常见错误一:把精确条件全放进 must,导致每个条件都参与评分,结果评分含义混乱。

常见错误二:对 text 字段使用 term 查询。term 不分析查询词,适合 keyword、数值、布尔等精确值;全文字段通常用 match

常见错误三:认为 filter 一定比 query 快。更准确的说法是 filter 不评分、适合缓存,但最终性能还取决于字段类型、基数、数据分布、缓存命中和查询组合。

六、常见误区与追问

条件建议上下文原因
match title: "Java 并发"query需要相关性评分和排序
term status: "published"filter只是硬条件,不需要评分
range created_at >= now-7dfilter时间窗口过滤,适合缩小结果集
should title^3 summary^2query用字段权重影响 _score
query: 这篇文档和“无线耳机”有多相关?
filter: 这篇文档是不是 sony,价格是不是 300~1500?

易错点:filter 不参与 _score,但“不评分”不等于任何 filter 都一定快,字段基数和数据分布仍然重要。

举个面试场景:搜索 Java 集合 时,标题和正文匹配应放 query;status=publishedtenant_id=42created_at>=now-30d 应放 filter。这样 _score 只表达内容相关性,不会被租户、状态、时间这些硬条件污染。

  • 误区:所有条件都放 must 更统一。 精确过滤条件放 must 会参与评分或影响评分语义,通常应放 filter
  • 误区:filter 一定会被缓存。 ES 会根据查询频率、成本、segment 等因素决定是否值得缓存,不能把缓存当成必然结果。
  • 误区:termmatch 只是写法不同。 term 不分析查询词,适合 keyword、数字、布尔;match 会分析文本,适合全文字段。
  • 追问:must_not 是否影响评分? must_not 处于过滤语义,只排除文档,不贡献 _score
  • 追问:为什么权限条件适合 filter? 权限是能不能看,不是相关不相关,放 filter 能保持评分只反映内容匹配程度。
  • 追问:排序字段显式指定后 _score 还有用吗? 如果完全按时间或价格排序,_score 可能不再作为主排序,但 query/filter 的语义区分仍影响匹配集合和计算成本。

七、加强记忆

记住“query 管相关性,filter 管硬条件”。全文检索、排序靠 query;状态、时间、权限、枚举过滤放 filter;bool 查询是把两者组合起来的标准姿势。