ES filter和post_filter的区别

news/2025/1/24 18:31:41/

ES filter和post_filter的区别

在Elasticsearch中,过滤搜索的结果是我们经常要做的事。在我刚开始接触 Elasticsearch,我就了解到有两种可以过滤搜索结果的方法。当时还不是很明白,为什么有的地方用 filter,而有的地方需要使用到 post_filter。在今天的文章中,我来用一个鲜活的例子来进行展示。

总体说来,我们可以使用如下的两个方法来过滤搜索的结果:

使用带有 filter 子句的布尔查询。搜索请求将布尔过滤器应用于搜索命中和聚合。

使用搜索 API 的 post_filter参数。搜索请求仅将 post_filter应用于搜索命中,而不是聚合。你可以使用 post_filter根据更广泛的结果集计算聚合,然后进一步缩小结果。讲得通俗一点:在已经计算聚合之后,post_filter 将应用于搜索请求最后的搜索命中。从这里的描述中,我们可以看出来,post_filter的使用和 aggregation 相关。

你还可以在 post_filter之后重新对命中进行评分,以提高相关性并重新排序结果

Post filter

当你使用 post_filter 参数过滤搜索结果时,会在计算聚合后过滤搜索命中。 Post filter 对聚合结果没有影响。

例如,你销售的衬衫具有以下属性:

java">PUT shirts{"mappings": {"properties": {"brand": { "type": "keyword"},"color": { "type": "keyword"},"model": { "type": "keyword"}}}}

我们使用如下的命令来摄入 3 个文档:

java">PUT shirts/_doc/1?refresh{"brand": "gucci","color": "red","model": "slim"}PUT shirts/_doc/2?refresh{"brand": "polo","color": "red","model": "large"}PUT shirts/_doc/3?refresh{"brand": "polo","color": "blue","model": "medium"}

假想你有一个用户,他想买一个 red 的衣服。通常你会使用如下的 bool query:

java">GET shirts/_search?filter_path=**.hits{"query": {"bool": {"filter": [{"term": {"color": "red"}}]}}}

上面显示的结果为:

java">{"hits" : {"hits" : [{"_index" : "shirts","_id" : "1","_score" : 0.0,"_source" : {"brand" : "gucci","color" : "red","model" : "slim"}},{"_index" : "shirts","_id" : "2","_score" : 0.0,"_source" : {"brand" : "polo","color" : "red","model" : "large"}}]}}

显然搜索的结果显示了所有 red 的衣服。但是,你还想使用分面导航来显示用户可以单击的其他选项列表(比如大小尺寸)。 也许你有一个 model 字段,允许用户将搜索结果限制为红色 Gucci T 恤或 Polo 的衣服。这可以通过 terms aggregation 来完成:

java">GET shirts/_search{"query": {"bool": {"filter": [{"term": {"color": "red"}}]}},"aggs": {"models": {"terms": {"field": "model"}}}}

在上面,我们通过 terms 聚合来显示各个尺寸(model)的文档数。最多的将排在前面。上面命令显示的结果为:

java">{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 2,"relation" : "eq"},"max_score" : 0.0,"hits" : [{"_index" : "shirts","_id" : "1","_score" : 0.0,"_source" : {"brand" : "gucci","color" : "red","model" : "slim"}},{"_index" : "shirts","_id" : "2","_score" : 0.0,"_source" : {"brand" : "polo","color" : "red","model" : "large"}}]},"aggregations" : {"models" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "large","doc_count" : 1},{"key" : "slim","doc_count" : 1}]}}}

在上面,我们可以看出颜色为 red 的衣服,各个 model 的统计情况:large 及 slim 个一件。显然这个是我们想要的结果。我们注意到的一点是 aggregation 是基于前面的 boolean filter 所过滤后的数据集来进行统计的。其统计结果都是是红色的衣服。

但也许你还想告诉用户有多少 polo 衬衫可供选择而不是所有的品牌。我们可以使用如下的搜索:

java">GET shirts/_search{"query": {"bool": {"filter": [{"term": {"color": "red"}}]}},"aggs": {"models": {"terms": {"field": "model"}}},"post_filter": {"term": {"brand": "polo"}}}

在上面,我们使用 filter 把 red 的文档搜索出来,然后使用 terms aggregatiion 来对所有 red 的文档进行 model 的统计。我们接下来使用 post_filter 来对我们的搜索结果再次过滤。在这里需要注意的是:post_filter 的使用不会对 aggs 的结果产生任何的影响。如同上面写的顺序一样,post_filter 是在最后面运行的。上面的命令产生的结果是:

java">{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.0,"hits" : [{"_index" : "shirts","_id" : "2","_score" : 0.0,"_source" : {"brand" : "polo","color" : "red","model" : "large"}}]},"aggregations" : {"models" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "large","doc_count" : 1},{"key" : "slim","doc_count" : 1}]}}}

如上所示,我们最终得到的搜索结果是 color:red 并且 brand:polo 的搜索结果,但是 aggregations 的结果是针对 color:red 而的出来的。我们可以看到上面的 slim 统计结果是来自 gucci 品牌的而不是 polo。

更为复杂的查询是这样的:

java">GET shirts/_search{"query": {"bool": {"filter": {"term": { "brand": "polo" }}}},"aggs": {"colors": {"terms": { "field": "color" }},"color_red": {"filter": {"term": { "color": "red" }},"aggs": {"models": {"terms": { "field": "model" }}}}},"post_filter": {"term": { "color": "red" }}}

在上面,我们首先使用的 filter 来过滤数据集。只有 brand:polo 的文档才可以进行聚合。aggs 里含有两个 aggregations。一个是按照 colors 来进行的分类,另外一个是先过滤 red 颜色的 polo,然后再按照 model 进行分类。在最后,我们使用 post_fitler 来过滤结果。最终的搜索结果(位于 hits 里)是 brand:polo 并且 color:red:

java">{"took" : 0,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.0,"hits" : [{"_index" : "shirts","_id" : "2","_score" : 0.0,"_source" : {"brand" : "polo","color" : "red","model" : "large"}}]},"aggregations" : {"color_red" : {"doc_count" : 1,"models" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "large","doc_count" : 1}]}},"colors" : {"doc_count_error_upper_bound" : 0,"sum_other_doc_count" : 0,"buckets" : [{"key" : "blue","doc_count" : 1},{"key" : "red","doc_count" : 1}]}}}

作者:Elasticsearch

链接:https://juejin.cn/post/7114169318669025316


http://www.ppmy.cn/news/1565848.html

相关文章

【负载均衡式在线OJ】加载题目信息(文件版)

目录 如何读取文件 -- 常见流程 代码 如何读取文件 -- 常见流程 在C中使用 std::ifstream来打开文件流是一个常见的操作,用于创建一个输入文件流,并尝试打开名为 question_list的文件。if (!in.is_open()):检查文件是否成功打开。如果文件未…

Windows安装Miniconda和PySide6以及配置PyCharm

目录 1. 选择Miniconda 2. 下载Miniconda 3. 安装Miniconda 4. 在base环境下创建pyside6环境 5. 安装pyside6环境 6. 配置PyCharm环境 7. 运行第一个程序效果 1. 选择Miniconda 选择Miniconda而没有选择Anaconda,是因为它是一个更小的Anaconda发行版&#x…

MySQL可直接使用的查询表的列信息

文章目录 背景实现方案模板SQL如何查询列如何转大写如何获取字符位置如何拼接字段 SQL适用场景 背景 最近产品找来,想让帮忙出下表的信息,字段驼峰展示,每张表信息show create table全部展示,再逐个粘贴,有点太耗费时…

算力需求大爆发,谁是“大推手”?

大约5亿年前,地球迎来了物种的突然大爆发,标志着生物进化除了缓慢渐变,还可能以跳跃的方式进行。 同样,人工智能在经历70余年曲折发展之后,也处于一个极为关键的时刻,在模型、数据、算力等各项基础技术多年…

【Leetcode 热题 100】279. 完全平方数

问题背景 给你一个整数 n n n,返回 和为 n n n 的完全平方数的最少数量 。 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如, 1 , 4 , 9 1,4,9 1,4,9 和 16 16 16 都是完…

NPM 与 Node.js 版本兼容问题:npm warn cli npm does not support Node.js

问题描述与处理策略 1、问题描述 npm warn cli npm v10.9.2 does not support Node.js v18.16.1. This version of npm supports the following node versions: ^18.17.0 || >20.5.0. You can find the latest version at https://nodejs.org/.# 翻译 npm warn cli npm v1…

一文了解 DeepSeek R1 模型:AI 推理领域的革命性突破

网址:DeepSeek 官方网站 2025 年 1 月 20 日,DeepSeek 发布了全新的开源推理大模型 DeepSeek-R1。 这一模型在数学、编程和推理等多个任务上达到了与 OpenAI o1 相当的表现水平,同时将 API 调用成本降低了 90-95%。 这一发布不仅引发了 AI …

GStreamer 简明教程(九):插件开发,以一个音频特效插件为例

系列文章目录 GStreamer 简明教程(一):环境搭建,运行 Basic Tutorial 1 Hello world! GStreamer 简明教程(二):基本概念介绍,Element 和 Pipeline GStreamer 简明教程(三…