ES filter和post_filter的区别
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 对聚合结果没有影响。
例如,你销售的衬衫具有以下属性:
PUT shirts
{
"mappings": {
"properties": {
"brand": { "type": "keyword"},
"color": { "type": "keyword"},
"model": { "type": "keyword"}
}
}
}
我们使用如下的命令来摄入 3 个文档:
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:
GET shirts/_search?filter_path=**.hits
{
"query": {
"bool": {
"filter": [
{
"term": {
"color": "red"
}
}
]
}
}
}
上面显示的结果为:
{
"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 来完成:
GET shirts/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"color": "red"
}
}
]
}
},
"aggs": {
"models": {
"terms": {
"field": "model"
}
}
}
}
在上面,我们通过 terms 聚合来显示各个尺寸(model)的文档数。最多的将排在前面。上面命令显示的结果为:
{
"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 衬衫可供选择而不是所有的品牌。我们可以使用如下的搜索:
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 是在最后面运行的。上面的命令产生的结果是:
{
"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。
更为复杂的查询是这样的:
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:
{
"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
原文地址:https://blog.csdn.net/Zhuxiaoyu_91/article/details/145327255
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!