搜索界面中的一个常见问题是您想要返回结果的选择,
但可能想返回有关所有文档的信息。 (例如,我想查看所有红色衬衫,但想知道什么
其他颜色可供选择)。
这有时被称为“多面结果”,或者
“多面导航”。这Elasticsearch 参考中的示例 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html非常清楚地解释了为什么/如何,所以
我用它作为这个问题的基础。
摘要/问题:看起来我可以为此使用后置过滤器或全局聚合。他们俩似乎
以不同的方式提供完全相同的功能。我认为它们可能有优点或缺点
没看到吗?如果是这样,我应该使用哪个?
我在下面提供了一个完整的示例,其中包含一些文档以及基于该示例的两种类型方法的查询
在参考指南中。
选项 1:后置过滤器
see the Elasticsearch 参考中的示例 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html
我们能做的是在我们的原始查询中获得更多结果,这样我们就可以聚合这些结果,然后
过滤我们的实际结果。
这个例子解释的很清楚:
但也许您还想告诉用户有多少种其他颜色的 Gucci 衬衫。如果您仅在颜色字段上添加术语聚合,则只会返回红色,因为您的查询仅返回 Gucci 的红色衬衫。
相反,您希望在聚合过程中包含所有颜色的衬衫,然后仅将颜色过滤器应用于搜索结果。
请参阅下面的示例代码,了解其外观。
这样做的一个问题是我们无法使用缓存。这是在(5.1 尚未提供)弹性搜索指南 https://www.elastic.co/guide/en/elasticsearch/guide/master/_post_filter.html警告:
性能考虑仅当您需要差异化过滤搜索结果和聚合时才使用 post_filter。有时人们会使用 post_filter 进行常规搜索。
不要这样做! post_filter 的本质意味着它在查询之后运行,因此过滤(例如缓存)的任何性能优势都将完全丧失。
post_filter 应该仅与聚合结合使用,并且仅在需要差分过滤时使用。
然而,还有一个不同的选择:
选项 2:全局聚合
有一种方法可以进行不受搜索查询影响的聚合。
因此,我们不是得到很多,而是对其进行聚合,然后进行过滤,我们只是得到过滤后的结果,但对它们进行聚合
一切。看一看在参考处 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-global-aggregation.html
我们可以得到完全相同的结果。我没有读到任何关于缓存的警告,但看起来最后
我们需要做大约相同数量的工作。所以这可能是唯一的遗漏。
由于我们需要子聚合(你不能有global
and a filter
于
同一水平')。
我读到的关于使用此查询的唯一抱怨是,如果您需要这样做,您可能必须重复自己
对于几个项目。最后我们可以生成大多数查询,因此重复自己对于我的用例来说并不是什么问题,
我并不认为这是与“无法使用缓存”同等的问题。
Question
看起来这两个功能至少有重叠,或者可能提供完全相同的功能。这让我很困惑。
除此之外,我想知道其中一个是否有我没有看到的优势,以及这里是否有任何最佳实践?
Example
这很大程度上来自于后置过滤器参考页 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-post-filter.html,但我添加了全局过滤器 https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-global-aggregation.html query.
地图和文件
PUT /shirts
{
"mappings": {
"item": {
"properties": {
"brand": { "type": "keyword"},
"color": { "type": "keyword"},
"model": { "type": "keyword"}
}
}
}
}
PUT /shirts/item/1?refresh
{
"brand": "gucci",
"color": "red",
"model": "slim"
}
PUT /shirts/item/2?refresh
{
"brand": "gucci",
"color": "blue",
"model": "slim"
}
PUT /shirts/item/3?refresh
{
"brand": "gucci",
"color": "red",
"model": "normal"
}
PUT /shirts/item/4?refresh
{
"brand": "gucci",
"color": "blue",
"model": "wide"
}
PUT /shirts/item/5?refresh
{
"brand": "nike",
"color": "blue",
"model": "wide"
}
PUT /shirts/item/6?refresh
{
"brand": "nike",
"color": "red",
"model": "wide"
}
我们现在要求所有红色 gucci 衬衫(第 1 项和第 3 项),我们为这 2 件衬衫提供的衬衫类型(修身版和普通版),
以及 gucci 有哪些颜色(红色和蓝色)。
首先,后置过滤器:获取所有衬衫,聚合红色 gucci 衬衫的型号和 gucci 衬衫的颜色(所有颜色),
红色 gucci 衬衫的后置过滤器仅显示结果:(这与示例有点不同,因为我们
尝试使其尽可能接近后置滤波器的清晰应用。)
GET /shirts/_search
{
"aggs": {
"colors_query": {
"filter": {
"term": {
"brand": "gucci"
}
},
"aggs": {
"colors": {
"terms": {
"field": "color"
}
}
}
},
"color_red": {
"filter": {
"bool": {
"filter": [
{
"term": {
"color": "red"
}
},
{
"term": {
"brand": "gucci"
}
}
]
}
},
"aggs": {
"models": {
"terms": {
"field": "model"
}
}
}
}
},
"post_filter": {
"bool": {
"filter": [
{
"term": {
"color": "red"
}
},
{
"term": {
"brand": "gucci"
}
}
]
}
}
}
我们还可以获取所有红色 gucci 衬衫(我们的原始查询),然后对模型进行全局聚合(对于所有
红色 gucci 衬衫)和颜色(适用于所有 gucci 衬衫)。
GET /shirts/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "color": "red" }},
{ "term": { "brand": "gucci" }}
]
}
},
"aggregations": {
"color_red": {
"global": {},
"aggs": {
"sub_color_red": {
"filter": {
"bool": {
"filter": [
{ "term": { "color": "red" }},
{ "term": { "brand": "gucci" }}
]
}
},
"aggs": {
"keywords": {
"terms": {
"field": "model"
}
}
}
}
}
},
"colors": {
"global": {},
"aggs": {
"sub_colors": {
"filter": {
"bool": {
"filter": [
{ "term": { "brand": "gucci" }}
]
}
},
"aggs": {
"keywords": {
"terms": {
"field": "color"
}
}
}
}
}
}
}
}
两者都将返回相同的信息,第二个仅因子聚合引入的额外级别而有所不同。第二个查询看起来有点复杂,但我认为这不是很有问题。现实世界的查询是由代码生成的,无论如何可能要复杂得多,它应该是一个很好的查询,如果这意味着复杂,那就这样吧。