elasticsearch - 分面搜索的后过滤器和全局聚合之间有什么区别?

标签 elasticsearch aggregate faceted-search elasticsearch-5

搜索界面中的一个常见问题是您想要返回一组结果,
但可能想要返回有关所有文档的信息。 (例如,我想看到所有的红色衬衫,但想知道什么
其他颜色可供选择)。

这有时被称为“分面结果”,或
“多面导航”。 example from the Elasticsearch reference很清楚地解释为什么/如何,所以
我用它作为这个问题的基础。

摘要/问题:看起来我可以为此同时使用后过滤器或全局聚合。他们俩似乎
以不同的方式提供完全相同的功能。他们可能有我认为的优点或缺点
没看见?如果是这样,我应该使用哪个?


我在下面包含了一个完整的示例,其中包含一些文档和基于示例的两种方法的查询
在引用指南中。

选项 1:后置过滤器

example from the Elasticsearch reference

我们可以做的是在我们的原始查询中有更多的结果,所以我们可以“聚合”这些结果,然后
过滤我们的实际结果。

这个例子很清楚地解释了它:

But perhaps you would also like to tell the user how many Gucci shirts are available in other colors. If you just add a terms aggregation on the color field, you will only get back the color red, because your query returns only red shirts by Gucci.

Instead, you want to include shirts of all colors during aggregation, then apply the colors filter only to the search results.



请参阅下面的示例代码中的内容。

一个问题是我们不能使用缓存。这是(5.1 尚不可用)elasticsearch guide警告:

Performance consideration Use a post_filter only if you need to differentially filter search results and aggregations. Sometimes people will use post_filter for regular searches.

Don’t do this! The nature of the post_filter means it runs after the query, so any performance benefit of filtering (such as caches) is lost completely.

The post_filter should be used only in combination with aggregations, and only when you need differential filtering.



然而,有一个不同的选择:

选项 2:全局聚合

有一种方法可以进行不受搜索查询影响的聚合。
因此,与其获取大量信息,然后对其进行聚合,然后进行过滤,我们只得到过滤后的结果,但对其进行聚合
一切。看看at the reference

我们可以得到完全相同的结果。我没有阅读任何关于缓存的警告,但似乎最终
我们需要做同样多的工作。所以这可能是唯一的遗漏。

由于我们需要的子聚合,它稍微复杂一点(您不能有 globalfilter同一级别')。

我读到的关于使用此查询的唯一提示是,如果您需要这样做,您可能不得不重复自己
对于几个项目。最后我们可以生成大多数查询,所以重复自己对我的用例来说不是什么大问题,
我并不认为这是与“无法使用缓存”同等的问题。

问题

似乎这两个功能至少重叠,或者可能提供完全相同的功能。这让我很困惑。
除此之外,我想知道其中一个或另一个是否有我没有看到的优势,以及这里是否有任何最佳实践?

示例

这主要来自 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),我们为这 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"
              }
            }
          }
        }
      }
    }
  }
}

两者都将返回相同的信息,第二个只是因为子聚合引入了额外的级别而有所不同。第二个查询看起来有点复杂,但我认为这不是很成问题。真实世界的查询是由代码生成的,无论如何可能会更复杂,它应该是一个很好的查询,如果这意味着复杂,那就这样吧。

最佳答案

在这两种情况下,Elasticsearch 最终都会做同样的事情。如果非要我选,我想我会用 global聚合,这可能会为您节省一些开销,而不必一次提供两个 Lucene 收集器。

关于elasticsearch - 分面搜索的后过滤器和全局聚合之间有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41285790/

相关文章:

lucene - 使用 RavenDb/Lucene 的分面搜索中的分层分类法?

Elasticsearch 内存不足错误

parameters - 从类路径加载器实例化时具有 null applicationContext 的 Axon SpringBeanParameterResolverFactory

mysql - 当函数中涉及非数字值时,sql返回空字符串?

r - 如何获得数据框中每个组的 10 个最高值?

solr - 将两个方面视为相同的值

drupal - 有人知道 Drupal 7 的多面搜索解决方案吗?

java - 使用 java 客户端 6.5 插入对象

elasticsearch - 如何在 .NET Core 3.1 的 appsettings 中配置 Serilog Elasticsearch 错误处理?

elasticsearch - ElasticSearch:Multi_fields参数不起作用