ElasticSearch5.X搜索条件的聚合(六)

范围限定的聚合

(测试数据:http://blog.csdn.net/wwd0501/article/details/78501842所有聚合的例子到目前为止,你可能已经注意到,我们的搜索请求省略了一个 query 。 整个请求只不过是一个聚合。

聚合可以与搜索请求同时执行,但是我们需要理解一个新概念: 范围 。 默认情况下,聚合与查询是对同一范围进行操作的,也就是说,聚合是基于我们查询匹配的文档集合进行计算的。

让我们看看第一个聚合的示例:

GET /cars/transactions/_search
{
    "size" : 0,
    "aggs" : {
        "colors" : {
            "terms" : {
              "field" : "color"
            }
        }
    }
}
我们可以看到聚合是隔离的。现实中,Elasticsearch 认为 "没有指定查询" 和 "查询所有文档" 是等价的。前面这个查询内部会转化成下面的这个请求:
GET /cars/transactions/_search
{
    "size" : 0,
    "query" : {
        "match_all" : {}
    },
    "aggs" : {
        "colors" : {
            "terms" : {
              "field" : "color"
            }
        }
    }
}
因为聚合总是对查询范围内的结果进行操作的,所以一个隔离的聚合实际上是在对  match_all 的结果范围操作,即所有的文档。

一旦有了范围的概念,我们就能更进一步对聚合进行自定义。我们前面所有的示例都是对 所有 数据计算统计信息的:销量最高的汽车,所有汽车的平均售价,最佳销售月份等等。

利用范围,我们可以问“福特在售车有多少种颜色?”诸如此类的问题。可以简单的在请求中加上一个查询(本例中为 match 查询):

GET /cars/transactions/_search
{
    "query" : {
        "match" : {
            "make" : "ford"
        }
    },
    "aggs" : {
        "colors" : {
            "terms" : {
              "field" : "color"
            }
        }
    }
}
因为我们没有指定  "size" : 0 ,所以搜索结果和聚合结果都被返回了:
{
...
   "hits": {
      "total": 2,
      "max_score": 1.6931472,
      "hits": [
         {
            "_source": {
               "price": 25000,
               "color": "blue",
               "make": "ford",
               "sold": "2014-02-12"
            }
         },
         {
            "_source": {
               "price": 30000,
               "color": "green",
               "make": "ford",
               "sold": "2014-05-18"
            }
         }
      ]
   },
   "aggregations": {
      "colors": {
         "buckets": [
            {
               "key": "blue",
               "doc_count": 1
            },
            {
               "key": "green",
               "doc_count": 1
            }
         ]
      }
   }
}

看上去这并没有什么,但却对高大上的仪表盘来说至关重要。 加入一个搜索栏可以将任何静态的仪表板变成一个实时数据搜索设备。 这让用户可以搜索数据,查看所有实时更新的图形(由于聚合的支持以及对查询范围的限定)。 这是 Hadoop 无法做到的!

Java代码实现:

/**
  	  * Description:带有搜索条件的聚合查询
  	  * 例:bmw(宝马)在售车有多少种颜色
  	  * 
  	  * @author wangweidong
  	  * CreateTime: 2017年11月10日 下午4:03:30
  	  *
  	 */
  	@Test
  	public void searchBucketsAggregation() {
  		String index = "cars";
  		String type = "transactions";
  		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index).setTypes(type);
  		
  		//搜索条件
  		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
  		queryBuilder.must(QueryBuilders.matchQuery("make", "bmw")); 
  		
  		//聚合
	    TermsAggregationBuilder field = AggregationBuilders.terms("popular_colors").field("color.keyword");
	    searchRequestBuilder.addAggregation(field);
//	    searchRequestBuilder.setSize(0);
	    searchRequestBuilder.setQuery(queryBuilder);
	    SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
	     
	    System.out.println(searchResponse.toString());
	    
	    Terms genders = searchResponse.getAggregations().get("popular_colors");
	    for (Terms.Bucket entry : genders.getBuckets()) {
	    	Object key = entry.getKey();      // Term
	        Long count = entry.getDocCount(); // Doc count
	        
	        System.out.println(key);
	        System.out.println(count);
	    }
  	}

 

全局桶

通常我们希望聚合是在查询范围内的,但有时我们也想要搜索它的子集,而聚合的对象却是 所有 数据。

例如,比方说我们想知道福特汽车与 所有 汽车平均售价的比较。我们可以用普通的聚合(查询范围内的)得到第一个信息,然后用 全局 桶获得第二个信息。

全局 桶包含 所有 的文档,它无视查询的范围。因为它还是一个桶,我们可以像平常一样将聚合嵌套在内:

GET /cars/transactions/_search
{
    "size" : 0,
    "query" : {
        "match" : {
            "make" : "ford"
        }
    },
    "aggs" : {
        "single_avg_price": {
            "avg" : { "field" : "price" } 
        },
        "all": {
            "global" : {}, 
            "aggs" : {
                "avg_price": {
                    "avg" : { "field" : "price" } 
                }

            }
        }
    }
}
        },
        "all": {
            "global" : {}, 
            "aggs" : {
                "avg_price": {
                    "avg" : { "field" : "price" } 
                }

            }
        }
    }
}

 

 

聚合操作在查询范围内(例如:所有文档匹配 ford )

 

global 全局桶没有参数。

 

聚合操作针对所有文档,忽略汽车品牌。

single_avg_price 度量计算是基于查询范围内所有文档,即所有 福特 汽车。avg_price 度量是嵌套在 全局 桶下的,这意味着它完全忽略了范围并对所有文档进行计算。聚合返回的平均值是所有汽车的平均售价。

如果能一直坚持读到这里,应该知道我们有个真言:尽可能的使用过滤器。它同样可以应用于聚合,在下一章中,我们会展示如何对聚合结果进行过滤而不是仅对查询范围做限定。

Java代码实现:

/**
  	 * Description:全局桶
  	 * 例:想知道福特(ford)汽车与 所有 汽车平均售价的比较
  	 * 
  	 * @author wangweidong
  	 * CreateTime: 2017年11月10日 下午4:03:30
  	 *
  	 */
  	@Test
  	public void globalBucketsAggregation() {
  		try {
  			String index = "cars";
  	  		String type = "transactions";
  	  		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index).setTypes(type);
  	  		
  	  		//搜索条件
  	  		BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
  	  		queryBuilder.must(QueryBuilders.matchQuery("make", "ford")); 
  	  		
  	  		//平均价格
  	  		AvgAggregationBuilder singleAvgPrice = AggregationBuilders.avg("single_avg_price").field("price");
  	  		
  	  		//聚合
  	  		GlobalAggregationBuilder field = AggregationBuilders.global("all");
  	        AvgAggregationBuilder avgPrice = AggregationBuilders.avg("avg_price").field("price");
  	        field.subAggregation(avgPrice);
  	  		
  	        searchRequestBuilder.addAggregation(singleAvgPrice);
  	  		searchRequestBuilder.addAggregation(field);
  		    searchRequestBuilder.setSize(0);
  	  		searchRequestBuilder.setQuery(queryBuilder);
  	  		SearchResponse searchResponse = searchRequestBuilder.execute().actionGet();
  	  		
  	  		System.out.println(searchResponse.toString());
  	  		
  	  		Avg avg = searchResponse.getAggregations().get("single_avg_price");
  	  		System.out.println("福特(ford)汽车平均价格:" + avg.getValue());
  	  		
  	  		Global global = searchResponse.getAggregations().get("all");
  	  		Avg allAvg = global.getAggregations().get("avg_price");
  	  		System.out.println("所有汽车平均价格:" + allAvg.getValue());
		} catch (Exception e) {
			e.printStackTrace();
		}
  	}

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值