过滤查询以及聚合
A natural extension to aggregation scoping is filtering. Because the aggregation operates in the context of the query scope, any filter applied to the query will also apply to the aggregation. 过滤是聚合作用域的一个很自然的扩展。因为聚合工作在查询作用域的上下文中,那么适用于查询的任何过滤器也同样能够适用于聚合。
filtered查询
如果你想要找到所有售价高于10000美刀的车,同时也对这些车计算其平均价格,那么可以使用一个filtered查询:
GET /cars/transactions/_search?search_type=count
"query" : {
"filtered": {
"filter": {
"range": {
"price": {
"gte": 10000
"aggs" : {
"single_avg_price": {
"avg" : { "field" : "price" }
从本质上而言,使用filtered查询和使用match查询并无区别,正如我们在上一章所讨论的那样。该查询(包含了一个过滤器)返回文档的一个特定子集,然后聚合工作在该子集上。
过滤桶(Filter Bucket)
如果你只想过滤聚合结果呢?假设我们正在创建针对汽车交易的搜索页面,我们想要根据用户搜索内容来展示对应结果。但是我们也想通过包含上个月出售的汽车的平均价格(匹配搜索的汽车)来让页面更加丰富。
此时我们不能使用简单的作用域,因为有两个不同搜索条件。搜索结果必须要匹配ford,但是聚合结果必须要匹配ford以及售出时间为上个月。
为了解决这一问题,我们使用一个名为filter的特殊桶。通过制定一个过滤器,当文档匹配了该过滤器的规则时,它就会被添加到桶中。
以下是得到的查询:
GET /cars/transactions/_search?search_type=count
"query":{
"match": {
"make": "ford"
"aggs":{
"recent_sales": {
"filter": {
"range": {
"sold": {
"from": "now-1M"
"aggs": {
"average_price":{
"avg": {
"field": "price"
因为过滤器桶和任何其它桶以相似的方式工作,你可以任意地将其它桶和指标包含在其中。所有的嵌套组建都会"继承"该过滤器。从而使你能够根据需要对聚合中的内容进行过滤。
后置过滤器(Post Filter)
目前,我们有了用于过滤搜索结果和聚合的过滤器(filtered查询),也有了用于过滤聚合中某一部分的过滤器(filter桶)。
你也许会好奇,“是否有一种过滤器只过滤搜索结果,而不过滤聚合呢?”这个问题的答案就是使用post_filter。
它是搜索请求内能够接受一个过滤器作为参数的顶层元素。该过滤器会在查询执行完毕后生效(后置因此得名:在查询执行之后运行)。正因为它在查询执行后才会运行,所以它并不会影响查询作用域 - 因此就不会对聚合有所影响。
我们可以利用这一行为在搜索条件中添加额外的过滤器,而不影响用户界面中类似于类别分面(Categorical Facets)的元素。让我们设计另一个针对汽车交易的搜索页面。该页面允许用户对汽车进行搜索,同时还能够根据颜色进行过滤。颜色通过聚合提供:
GET /cars/transactions/_search?search_type=count
"query": {
"match": {
"make": "ford"
"post_filter": {
"term" : {
"color" : "green"
"aggs" : {
"all_colors": {
"terms" : { "field" : "color" }
post_filter元素是一个顶层元素,只会对搜索结果进行过滤。
查询部分呢用来找到所有ford汽车。然后我们根据一个terms聚合来得到颜色列表。因为聚合是在查询作用域中进行的,得到的颜色列表会反映出ford汽车的各种颜色。
最后,post_filter会对搜索结果进行过滤,只显示绿色的ford汽车。这一步发生在执行查询之后,因此聚合是不会被影响的。
这一点对于维持一致的用户界面而言是非常重要的。假设一个用户在界面上点击了一个分类(比如,绿色)。期望的结果是搜索结果被过滤了,而用户界面上的分类选项是不会变化的。如果你使用了一个filtered查询,用户界面上也立即会对分类进行更新,此时绿色就变成了唯一的选项 - 这显然不是用户想要的!
警告:性能考量
只有当你需要对搜索结果和聚合使用不同的过滤方式时才考虑使用post_filter。有时一些用户会直接在常规搜索中使用post_filter。
不要这样做!post_filter会在查询之后才会被执行,因此会失去过滤在性能上帮助(比如缓存)。
post_filter应该只和聚合一起使用,并且仅当你使用了不同的过滤条件时。
选择合适类型的过滤 - 搜索结果(Search Hits),聚合(Aggregations),或两者 - 通常都取决于你的用户界面的行为。过滤器的选择(或者组合)取决于你想要如何向用户展示结果数据。
- A filtered query affects both search results and aggregations.filtered查询会影响搜索结果和聚合。
- filter桶只影响聚合。
- post_filter只影响搜索结果。
1、线上问题如上所示,问题是:“把 green 这个条件放到 query 里面做一个 bool
查询,有什么不一样吗?”2、拿官方样例飞行数据举例这个问题涉及到:filter(
过滤器)和 post_filter(后
过滤器)的区别,我们拿官方样例索引:kibana_sample_data_flights 做一样演示。3、filter
过滤+
聚合的场景直接上 DSL,检索条件...
由于最近在使用spring+jersey开发要设置基于servlet的filter。当在filter中通过request.getReader或者getInputStream读取body中的json参数处理时,由于rest风格的jersey框架底层亦是基于同样原理读取post请求body中参数。因为request自身的原则:getReader或者getInputStream只能调用其中一个且只有一次
在
Elasticsearch 中,
过滤搜索的结果是我们经常要做的事。在我刚开始接触
Elasticsearch,我就了解到有两种可以
过滤搜索结果的方法。当时还不是很明白,为什么有的地方用 filter,而有的地方需要使用到 post filter。在今天的文章中,我来用一个鲜活的例子来进行展示。
总体说来,我们可以使用如下的两个方法来
过滤搜索的结果:
使用带有 filter 子句的布尔
查询。
搜索请求将布尔
过滤器应用于
搜索命中和
聚合。
使用
搜索 API 的 post_filter 参数。
搜索请求
平常的
过滤我们可以
查询然后包括一个
过滤器 (filter) 返回一组文档的子集但是如果我们只想对
聚合结果
过滤怎么办?定义当前文档集上下文中匹配指定
过滤器(filter)的所有文档的单个桶。参数,以便向响应中添加一个桶,该桶将包含不匹配任何给定的
过滤器的所有文档。我们可以指定一个
过滤桶,当文档满足
过滤桶的条件时,我们将其加入到桶内。这里我们无法简单的做范围限定,因为有两个不同的条件。)的桶,否则(使用匿名
过滤器时)就是返回的桶中的最后一个。
过滤后的桶按照请求中给定的顺序返回。桶的键,以取代默认的。
我们可能会想,“只
过滤搜索结果,不
过滤聚合结果呢?” 答案是使用 post_filter。它是接收一个
过滤器的顶层
搜索请求元素。这个
过滤器在
查询 之后 执行(这正是该
过滤器的名字的由来:它在
查询之后 post 执行)。正因为它在
查询之后执行,它对
查询范围没有任何影响,所以对
聚合也不会有任何影响。
文章目录1. bool 和 filtered2. filter的两种用法
1. bool 和 filtered
es 5.0版本更新后,filtered的
查询将替换为bool
查询。
filtered是比较老的的版本的语法。现在目前已经被bool替代。推荐使用bool。
官方文档地址:链接
2. filter的两种用法
嵌套在bool下
"query": {
"bool": ...
query与filter的合并将filter的api列为deprecated,然后合并到query里头。之后
查询的context就分为query的context和filter的context。凡是不是filter的context就走query的context。filter的话,其结果不参与score计算,而且会缓存,可能相对快一些。判断是否属于filter contextthe constant_...
查询state为MD的数据,并且根据
查询后的结果,以城市city
聚合,显示
查询结果和
聚合结果:
查询1:POST /bank/_search{"size": 30,"query": {"bool": {"filter": {"term": {"state.keyword": "MD"}}}},"aggs": {"cities": {"terms": {"size": 30,"field": "cit...
Elasticsearch的
聚合结果是先
过滤或者
搜索后
聚合,那么如果我们想要先
聚合,然后对结果进行再一次的
过滤或者
搜索应该如何实现呢,在此给出简单的java实现demo