ElasticSearch在多个字段上进行过滤(使用聚合)

时间:2022-05-04 11:48:48

I am building a faceted filtering function for a webshop, something like this:

我正在为网店建立一个分面过滤功能,如下所示:

Filter on Brand:
[ ] LG (10)
[ ] Apple (5)
[ ] HTC (3)

Filter on OS:
[ ] Android 4 (11)
[ ] Android 5 (2)
[ ] IOS (5)

I am using aggregation and filtering in elasticsearch, which is working out pretty well for me after a few days of learning ES (loving it!). But sadly I got stuck on the actual filtering now.

我在弹性搜索中使用聚合和过滤,在学习ES(喜欢它!)几天后,这对我来说非常好。但遗憾的是,我现在卡在了实际的过滤上。

If i click on 'LG', the IOS filter will be disabled and (5) will change to (0) and the results on the right side will change to 13 android phones. Great, so far so good.

如果我点击“LG”,IOS过滤器将被禁用,(5)将变为(0),右侧的结果将变为13个Android手机。很棒,到目前为止一切顺利。

Now if I click on 'Android 4', only 11 phones will show on the right side. Awesome! So far so good :)

现在,如果我点击“Android 4”,右侧只会显示11部手机。真棒!到现在为止还挺好 :)

But now, if i click on 'Android 5', all results disappear. I'm not sure what I'm doing wrong. I would expect that all LG phones with both Android 4 and 5 show up.

但现在,如果我点击“Android 5”,所有结果都会消失。我不确定我做错了什么。我希望所有同时拥有Android 4和5的LG手机都会出现。

Below is a sample query of the last case. Please note there are also some other fields included in the query which I am using to build the faceted filtering.

以下是最后一个案例的示例查询。请注意,查询中还包含一些其他字段,用于构建分面过滤。

{
   "size":100,
   "query":{
      "filtered":{
         "query":{
            "match_all":[

            ]
         },
         "filter":{
            "bool":{
               "must":[
                  {
                     "term":{
                        "brand.untouched":"LG"
                     }
                  },
                  {
                     "term":{
                        "operating_system.untouched":"Android 4"
                     }
                  },
                  {
                     "term":{
                        "operating_system.untouched":"Android 5"
                     }
                  }
               ],
               "should":[

               ],
               "must_not":{
                  "missing":{
                     "field":"model"
                  }
               }
            }
         },
         "strategy":"query_first"
      }
   },
   "aggs":{
      "brand.untouched":{
         "terms":{
            "field":"brand.untouched"
         }
      },
      "operating_system.untouched":{
         "terms":{
            "field":"operating_system.untouched"
         }
      },
      "camera1":{
         "histogram":{
            "field":"camera1",
            "interval":5,
            "min_doc_count":0
         }
      },
      "price_seperate":{
         "histogram":{
            "field":"price_seperate",
            "interval":125,
            "min_doc_count":0
         }
      }
   }
}

Does anyone know the solution? Thanks so much.

有谁知道解决方案?非常感谢。

1 个解决方案

#1


Your query is searching for documents in which operating_system.untouched is both "Android 4" and "Android 5" which will never be the case and hence you get zero results. You can simply make use of Terms Filter so that documents where the value of operating_system.untouched is either "Android 4" or "Android 5" matches. Below is the updated query you should be using:

您的查询正在搜索其中operating_system.untouched为“Android 4”和“Android 5”的文档,这些文档永远不会出现这种情况,因此您的结果为零。您可以简单地使用术语过滤器,以使operating_system.untouched的值为“Android 4”或“Android 5”的文档匹配。以下是您应该使用的更新查询:

{
   "size":100,
   "query":{
      "filtered":{
         "filter":{
            "bool":{
               "must":[
                  {
                     "terms":{
                        "brand.untouched": [
                            "LG"
                        ]
                     }
                  },
                  {
                     "terms":{
                        "operating_system.untouched": [
                            "Android 4",
                            "Android 5"
                        ]
                     }
                  }
               ],
               "must_not":{
                  "missing":{
                     "field":"model"
                  }
               }
            }
         },
         "strategy":"query_first"
      }
   },
   "aggs":{
      "brand.untouched":{
         "terms":{
            "field":"brand.untouched"
         }
      },
      "operating_system.untouched":{
         "terms":{
            "field":"operating_system.untouched"
         }
      },
      "camera1":{
         "histogram":{
            "field":"camera1",
            "interval":5,
            "min_doc_count":0
         }
      },
      "price_seperate":{
         "histogram":{
            "field":"price_seperate",
            "interval":125,
            "min_doc_count":0
         }
      }
   }
}

If you want to add another set of categories like price range, you just need to add a bool should clause inside the bool must clause. See below for an example when you want to filter on a field price on two ranges (0, 100] and (100, 200]. What this basically means is that you can have nested must and should filters to realize any boolean logic you want to implement for filtering in Elasticsearch.

如果你想添加另一组类别,比如价格范围,你只需要在bool must子句中添加一个bool should子句。当您想要在两个范围(0,100)和(100,200)上的字段价格上进行过滤时,请参阅下面的示例。这基本上意味着您可以使用嵌套必须和过滤器来实现您想要的任何布尔逻辑在Elasticsearch中实现过滤。

... 
"must":[
    {
        "terms":{
            "brand.untouched": [
                "LG"
            ]
        }
    },
    {
        "terms":{
            "operating_system.untouched": [
               "Android 4",
               "Android 5"
            ]
        }
    },
    "bool": {
        "should": [
            {
                "range": {
                    "price": {
                        "gt": 0,
                        "lte": 100
                    }
                }
            },
            {
                "range": {
                    "price": {
                        "gt": 100,
                        "lte": 200
                    }
                }
            }
        ]
    }
],
...

#1


Your query is searching for documents in which operating_system.untouched is both "Android 4" and "Android 5" which will never be the case and hence you get zero results. You can simply make use of Terms Filter so that documents where the value of operating_system.untouched is either "Android 4" or "Android 5" matches. Below is the updated query you should be using:

您的查询正在搜索其中operating_system.untouched为“Android 4”和“Android 5”的文档,这些文档永远不会出现这种情况,因此您的结果为零。您可以简单地使用术语过滤器,以使operating_system.untouched的值为“Android 4”或“Android 5”的文档匹配。以下是您应该使用的更新查询:

{
   "size":100,
   "query":{
      "filtered":{
         "filter":{
            "bool":{
               "must":[
                  {
                     "terms":{
                        "brand.untouched": [
                            "LG"
                        ]
                     }
                  },
                  {
                     "terms":{
                        "operating_system.untouched": [
                            "Android 4",
                            "Android 5"
                        ]
                     }
                  }
               ],
               "must_not":{
                  "missing":{
                     "field":"model"
                  }
               }
            }
         },
         "strategy":"query_first"
      }
   },
   "aggs":{
      "brand.untouched":{
         "terms":{
            "field":"brand.untouched"
         }
      },
      "operating_system.untouched":{
         "terms":{
            "field":"operating_system.untouched"
         }
      },
      "camera1":{
         "histogram":{
            "field":"camera1",
            "interval":5,
            "min_doc_count":0
         }
      },
      "price_seperate":{
         "histogram":{
            "field":"price_seperate",
            "interval":125,
            "min_doc_count":0
         }
      }
   }
}

If you want to add another set of categories like price range, you just need to add a bool should clause inside the bool must clause. See below for an example when you want to filter on a field price on two ranges (0, 100] and (100, 200]. What this basically means is that you can have nested must and should filters to realize any boolean logic you want to implement for filtering in Elasticsearch.

如果你想添加另一组类别,比如价格范围,你只需要在bool must子句中添加一个bool should子句。当您想要在两个范围(0,100)和(100,200)上的字段价格上进行过滤时,请参阅下面的示例。这基本上意味着您可以使用嵌套必须和过滤器来实现您想要的任何布尔逻辑在Elasticsearch中实现过滤。

... 
"must":[
    {
        "terms":{
            "brand.untouched": [
                "LG"
            ]
        }
    },
    {
        "terms":{
            "operating_system.untouched": [
               "Android 4",
               "Android 5"
            ]
        }
    },
    "bool": {
        "should": [
            {
                "range": {
                    "price": {
                        "gt": 0,
                        "lte": 100
                    }
                }
            },
            {
                "range": {
                    "price": {
                        "gt": 100,
                        "lte": 200
                    }
                }
            }
        ]
    }
],
...