如何在弹性搜索OR选项中使用term-aggregations

时间:2014-07-30 07:51:26

标签: elasticsearch filter aggregation facets

假设我有以下数据:

car1: { color: blue, brand: mercedes }
car2: { color: blue, brand: toyota }
car3  { color: red,  brand: mercedes }
car4: { color: red,  brand: toyota }
car5: { color: green,brand: toyota }

" color"的聚合给了我{ blue: 2, red: 2, green: 1}

"品牌"的汇总给了我{ mercedes: 2, toyota: 3 }

到目前为止很好。

如果我搜索" color = blue"并在过滤后进行我的聚合,最终得到:

聚合"颜色"给我{ blue: 2 } //仅适用于蓝色汽车

聚合"品牌"给我{ mercedes: 1, toyota: 1 } //仅适用于蓝色汽车

在我的搜索中,我可能会为每个属性选择多个方面,因此搜索"蓝色"或"红色"或"绿色"汽车会给我所有记录。

所以我希望在过滤相应属性之前得到每个聚合值,但是在其他属性之后,我也可以看到其他数量。

此处不适用使用后置过滤器(循环引用)。

我是否真的需要触发多个查询(主查询和每个聚合)?

或者我必须在后过滤之前使用所有聚合并在每个聚合中再次放置除了相应的所有过滤器(filter-aggr。)?

任何帮助表示赞赏!


[A]
没有过滤器

Color:
  ( ) blue: 2
  ( ) red: 2
  ( ) green: 1
Brand:
  ( ) toyota: 3
  ( ) mercedes: 2

[B]
过滤:color = blue

Color:
  (x) blue: 2
Brand:
  ( ) toyota: 1
  ( ) mercedes: 1

[C]
过滤:color = blue

Color:
  (x) blue: 2
  ( ) red: 2
  ( ) green: 1
Brand:
  ( ) toyota: 1
  ( ) mercedes: 1

3 个答案:

答案 0 :(得分:3)

根据您想要的上述示例功能,以下是一些可以帮助您实现的查询。

例如B: 此查询仅为您提供整个查询的聚合。第一次在页面加载时运行,查询部分中没有任何条款,因此您将获得颜色和品牌的完整聚合列表。如果用户选择了蓝色构面,则查询将仅返回与该构面匹配的文档。这意味着从返回的集合生成的聚合将与示例B中的构面列表匹配。

POST /cars/car/_search
{
    "query": {
        "term": {
           "color": {
              "value": "blue"
           }
        }
    }, 
    "aggs" : {
        "colors" : {
            "terms" : { "field" : "color" }
        },
        "brands" : {
            "terms" : { "field" : "brand" } 
        }
    }
}

示例C: 对于示例C,我相信您的目标是即使在执行搜索之后,所有可能的方面也应该是可见的。为此,您需要创建一个使用全局上下文来获取所有文档的聚合,而不仅仅是查询返回的文档。在此示例中,所有搜索都将返回颜色和品牌的完整构面列表。

POST /cars/car/_search
{
    "query": {
        "term": {
           "color": {
              "value": "blue"
           }
        }
    }, 
    "aggs" : {
        "all_cars" : {
            "global": {},
            "aggs" : {
                "colors" : {
                    "terms" : { "field" : "color" }
                },
                "brands" : {
                    "terms" : { "field" : "brand" }
                }
            }
        }
    }
}

如果您的目标是允许用户始终查看所有可用方面,请确保您的查询根据用户选择的方面的数量和类型进行自我调整。

更新:根据以下评论,这将结合两个选项。您可以通过这种方式获得完整的未过滤聚合和过滤的聚合。您必须以编程方式根据用户的操作决定在显示中使用哪个方面列表。

POST /cars/car/_search
{
    "query": {
        "term": {
           "color": {
              "value": "blue"
           }
        }
    }, 
    "aggs" : {
        "colors" : {
            "terms" : { "field" : "color" }
        },
        "brands" : {
            "terms" : { "field" : "brand" } 
        },
        "all_cars" : {
                "global": {},
                "aggs" : {
                    "colors" : {
                        "terms" : { "field" : "color" }
                    },
                    "brands" : {
                        "terms" : { "field" : "brand" }
                }
            }
        }
    }
}

更新2:您还可以嵌套聚合,以便您可以通过过滤器预先计算各个方面。

POST /cars/car/_search
{
    "aggs" : {
        "colors" : {
            "terms" : { "field" : "color" },
            "aggs" : {
                "brandsByColor" : {
                    "terms" : { "field" : "brand" }
                }
            }
        },
        "brands" : {
            "terms" : { "field" : "brand" },
            "aggs" : {
                "colorsByBrand" : {
                    "terms" : { "field" : "color" }
                }
            }
        }
    }
}

答案 1 :(得分:1)

我遇到了同样的问题并设法解决了。

您需要ElasticSearch 1.4才能执行此操作,并使用过滤器聚合和" postfilters"来实现。 在1.4之前,我使用过滤查询执行此操作以获得正确的聚合计数,并尝试使用" global:{},filter:{}"聚合。就像在上面的答案。问题是全局{}聚合会忽略查询本身,如果您正在对过滤进行全文搜索,则它将无效。

现在是1.4。您所要做的就是运行正常的未过滤查询并将后过滤器应用于它。对于聚合,您使用过滤器聚合,您可以应用所有后置过滤器,除了应用聚合的现场之外。

因此,在您的示例中,您将在颜色和品牌上都有一个AND postfilter。在颜色聚合中,您将拥有品牌过滤器,而在品牌聚合中,您将拥有颜色过滤器。

在我的情况下,我有company_id和主题过滤器。以前我会这样做,但它只适用于match_all查询。

POST /cars/car/_search
{
    "size": "20",
    "from": "0",
    "aggs": {
        "company_id": {
            "terms": {
                "field": "company_id",
                "size": 10
            }
        },
        "global_company": {
            "global": {},
            "aggs": {
                "company_id_3": {
                    "filter": {
                        "term": {
                            "subjects": "710"
                        }
                    },
                    "aggs": {
                        "company_id_2": {
                            "terms": {
                                "field": "company_id"
                            }
                        }
                    }
                }
            }
        }
    },
    "sort": [
        {
            "_score": "desc"
        }
    ],
    "query": {
        "filtered": {
            "query": {
                "match_all": {}
            },
            "filter": {
                "and": [
                    {
                        "term": {
                            "company_id": "1215"
                        }
                    },
                    {
                        "term": {
                            "subjects": "710"
                        }
                    }
                ]
            }
        }
    }
}

现在我这样做了,它适用于所有人:

POST /cars/car/_search
{
    "size": "20",
    "from": "0",
    "aggs": {
        "company_id": {
            "terms": {
                "field": "company_id",
                "size": 10
            }
        },
        "global_company": {
            "global": {},
            "aggs": {
                "company_id_3": {
                    "filter": {
                        "term": {
                            "subjects": "710"
                        }
                    },
                    "aggs": {
                        "company_id_2": {
                            "terms": {
                                "field": "company_id"
                            }
                        }
                    }
                }
            }
        }
    },
    "sort": [
        {
            "_score": "desc"
        }
    ],
    "query": {
        "match_all": {}
    },
    "filter": {
        "and": [
            {
                "term": {
                    "company_id": "1215"
                }
            },
            {
                "term": {
                    "subjects": "710"
                }
            }
        ]
    }
}

您可以看到我如何仅在company_id_3聚合上应用其他过滤器。在这里你可以用任何令你满意的查询替换match_all查询,你仍然可以得到你需要的OR逻辑

答案 2 :(得分:0)

  

或者我必须在后过滤之前使用所有聚合并放入所有聚合   除了每个聚合中的相应对应的过滤器   (过滤汇聚。)?

这样做。