--- title: "Elasticsearch filter context 的实践案例" date: 2024-12-15 lastmod: 2024-12-15 description: "本文通过两个案例分析 Elasticsearch 中 filter context 的使用效果,对比 must 和 filter 条件在缓存利用和查询性能上的差异,指出并非所有 filter 查询都能加速,并探讨了底层 ConstantScore 查询对缓存的影响,同时提供校验思路与工具。" tags: ["Elasticsearch", "filter", "practice"] summary: "知识背景 # 在 ES 查询优化的建议里,很多时候为了避免算分逻辑和利用缓存逻辑,Elastic 会建议大家使用 filter 条件。 filter 的使用条件和原理具体可以参照之前写的博文《Elasticsearch filter context 的使用原理》(https://mp.weixin.qq.com/s/Jsgx_RL0T794Z2bxuKtqOA) 这里我们来研究 2 个实用案例,具体的感受一下 filter context 的使用效果。 普通案例 # 第一个案例,我们选择一个 range date 的条件进行测试环境测试,将其中 must 条件改成 filter 条件,测试 5 次以上,观测其缓存数据。 # 清空缓存 POST indexname/_cache/clear?query=true # 查询 5-10 次 GET indexname/_search { "query": { "bool": { "must": [ { "range": { "date": { "gte": "2024-01-01", "lte": "2024-03-01" } } } ] } } } # 查询缓存状态 GET indexname/_stats?human=true&filter_path=*.*.query_cache ​ 可以看到 query_cache 的 size/count 始终为 0,也就是并没有利用到缓存。" --- ## 知识背景 在 ES 查询优化的建议里,很多时候为了避免算分逻辑和利用缓存逻辑,Elastic 会建议大家使用 filter 条件。 filter 的使用条件和原理具体可以参照之前写的博文《Elasticsearch filter context 的使用原理》(https://mp.weixin.qq.com/s/Jsgx_RL0T794Z2bxuKtqOA) 这里我们来研究 2 个实用案例,具体的感受一下 filter context 的使用效果。 ## 普通案例 第一个案例,我们选择一个 range date 的条件进行测试环境测试,将其中 must 条件改成 filter 条件,测试 5 次以上,观测其缓存数据。 ``` # 清空缓存 POST indexname/_cache/clear?query=true # 查询 5-10 次 GET indexname/_search { "query": { "bool": { "must": [ { "range": { "date": { "gte": "2024-01-01", "lte": "2024-03-01" } } } ] } } } # 查询缓存状态 GET indexname/_stats?human=true&filter_path=*.*.query_cache ​ ``` 可以看到 query_cache 的 size/count 始终为 0,也就是并没有利用到缓存。 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter1.png" "" %}} 查询的耗时也维持在 900-1100ms 左右。 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter2.png" "" %}} 再测试 filter 条件 ``` POST indexname/_cache/clear?query=true # 查询 5-10 次 GET indexname/_search { "query": { "bool": { "filter": [ { "range": { "date": { "gte": "2024-01-01", "lte": "2024-03-01" } } } ] } } } ​ GET indexname/_stats?human=true&filter_path=*.*.query_cache ​ ``` 在重复的查询过程中,查询速度有明显的加快。 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter3.png" "" %}} 多次查询之后 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter4.png" "" %}} 查看 query_cache size/count 有明显的使用。 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter5.png" "" %}} ## 使用误区 那是不是所有的 filter 就会加速呢?再看下面这个查询 must 方法 ``` GET indexname/_search { "query": { "bool": { "must": [ { "terms": { "idno": [ "2024001Q0001235681", "2024001Q0002356812", "2024001Q0008197301", "2024001Q0002817617" ] } } ] } } } ``` {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter6.png" "" %}} filter 方法 ``` GET indexname/_search { "query": { "bool": { "filter": [ { "terms": { "idno": [ "2024001Q0001235681", "2024001Q0002356812", "2024001Q0008197301", "2024001Q0002817617" ] } } ] } } } ​ ``` {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter7.png" "" %}} 可以看到 2 个查询条件多次查询后,查询耗时差别不大。 并且**都产生了 query cache 的使用**。 must 条件 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter8.png" "" %}} filter 条件 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter9.png" "" %}} 难道这两个查询都成了 filter context 查询?既然 **filter context 的判断依据之一是查询条件是否算分**,就可以使用 "explain": true 进行进一步分析。 must 方法 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter10.png" "" %}} filter 方法 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter11.png" "" %}} 可以看到查询方法在 ES 这里做了隐性的转换。这两个查询对应的**底层查询方法为 ConstantScore**,而 ConstantScore 也是可以被认为是 filter context 的一种。因此这里的 must 查询也达到 filter 查询使用 querycache 的优势。 ## 校验思路 {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter12.png" "" %}} - cache 数据 ``` GET indexname/_stats?human=true&filter_path=*.*.query_cache ``` 也可以通过简单安装一个 INFINI Console(https://docs.infinilabs.com/console/main/docs/getting-started/install/) 进行图表监控(在监控图表-索引-advance 中) {{% load-img "/img/blog/2024/elasticsearch-filter-context-practice/filter13.png" "" %}} - 查询使用的算分方法 利用 explain API 判断查询语句是否转换成符合 filter context 的类型,比如是否转换成了 constant score,或者算分规则被消除了,等等 ``` GET indexname/_search {"explain": true, "query": { "bool": { "filter": [ { "terms": { "idno": [ "2024001Q0001235681", "2024001Q0002356812", "2024001Q0008197301", "2024001Q0002817617" ] } } ] } } } ```