搜索界面中的一个常见问题是您要返回一系列结果, 但可能想要返回有关所有文档的信息。 (例如,我想看到所有的红色衬衫,但想知道什么 其他颜色可供选择。)
这有时被称为"分面结果"或 "分面导航"。 example from the Elasticsearch reference在解释原因/方式时非常清楚 我已将此作为此问题的基础。
摘要/问题:看起来我可以同时使用后置过滤器或全局聚合。他们似乎都是 以不同的方式提供完全相同的功能。我可能有优点或缺点 不明白吗?如果是这样,我应该使用哪个?
我在下面提供了一个完整的示例,其中包含一些文档和基于示例的两种方法的查询 在参考指南中。
选项1:后置过滤器
请参阅example from the Elasticsearch reference
我们可以做的是在我们的原始查询中获得更多结果,因此我们可以汇总' on'那些结果,以及之后 过滤我们的实际结果。
这个例子非常清楚地解释了它:
但也许您还想告诉用户其他颜色有多少Gucci衬衫可供选择。如果您只是在颜色字段上添加术语聚合,则只会返回红色,因为您的查询仅返回Gucci的红色衬衫。
相反,您希望在聚合过程中包含所有颜色的衬衫,然后仅将颜色过滤器应用于搜索结果。
在示例代码中查看下面的内容。
这个问题是我们不能使用缓存。这是({尚未提供给5.1)elasticsearch guide警告:
效果考虑 仅当您需要差异过滤搜索结果和聚合时,才使用post_filter。有时人们会使用post_filter进行常规搜索。
不要这样做! post_filter的性质意味着它在查询之后运行,因此过滤(例如缓存)的任何性能优势都会完全丢失。
post_filter只能与聚合一起使用,并且仅在您需要差异过滤时使用。
但是有一个不同的选择:
选项2:全球汇总
有一种方法可以进行不受搜索查询影响的聚合。 因此,不是得到很多,聚合,然后过滤,我们只是得到我们的过滤结果,但做聚合 一切。看看at the reference
我们可以得到完全相同的结果。我没有阅读有关缓存的任何警告,但最终似乎是这样 我们需要做同样多的工作。所以这可能是唯一的遗漏。
由于我们需要的子聚合,它有点复杂(你不能拥有global
和filter
相同的'水平')。
我读到的关于使用此查询的唯一投诉是,如果您需要这样做,您可能需要重复自己 几个项目。最后我们可以生成大多数查询,所以重复自己并不是我的用例的问题, 我并不认为这是一个与&#34相同的问题;不能使用缓存"。
问题
似乎两个函数至少重叠,或者可能提供完全相同的功能。这令我感到困惑。 除此之外,我想知道一个或另一个是否有我没见过的优势,以及这里是否有最好的做法?
示例
这主要来自post-filter reference page,但我添加了global filter查询。
地图和文件
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项),这两件衬衫的衬衫类型(纤细和正常), 和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"
}
}
}
}
}
}
}
}
两者都将返回相同的信息,第二个仅因子聚合引入的额外级别而不同。第二个查询看起来有点复杂,但我不认为这是非常有问题的。一个真实世界的查询是由代码生成的,可能更复杂,它应该是一个很好的查询,如果这意味着复杂,那就这样吧。
答案 0 :(得分:1)
在这两种情况下,Elasticsearch最终都会做同样的事情。如果我必须选择,我想我会使用global
聚合,这可能会为您免于一次为两个Lucene收集器提供一些开销。
答案 1 :(得分:1)
我们使用的实际解决方案虽然不是问题的直接答案,但基本上都不是“。”
从this elastic blogpost我们得到了最初的提示:
偶尔,我会看到一个过于复杂的搜索,其目标是尽可能少地搜索请求。这些过滤器往往尽可能晚,完全与Filter First中的建议相反。不要害怕使用多个搜索请求来满足您的信息需求。多搜索API允许您发送一批搜索请求。
请勿将所有内容整理成一个搜索请求。
这基本上就是我们在上面的查询中所做的:一大堆聚合和一些过滤。
让它们并行运行证明要快得多。看看the multi-search API