ES聚合学习(三)
es聚合
#ES中的聚合操作 参与聚合的字段必须是keword、数值、日期、布尔
#1.Bucket桶聚合(文档字段分组,日期分组)2.Metric度量聚合(最大值,最小值,平均值)
#3.Pipeline管道聚合(其他聚合的结果为基础做聚合)
#桶聚合 第一个size:聚合中不包含文档,只包含聚合结果。size:希望获得聚合结果的数量 doc_count:是文档数量,桶里面有几条文档啊,是倒叙排序
#统计所有数据中酒店品牌有几种
GET /hotel/_search
{
"size":0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 10
}
}
}
}
#更改排序、添加限定聚合搜索的范围
GET /hotel/_search
{
"query": {
"range": {
"price": {
"gte": 0,
"lte": 200
}
}
},
"size":0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"order": {
"_count": "asc"
},
"size": 10
}
}
}
}
#Metrics聚合
#统计每个品牌用户的评分的最大值、最小值 排序根据平均降序分排序
#里面的aggs是对brand的子聚合,也就是分组后对分组分别计算 stats:可以计算min、max、avg...
GET /hotel/_search
{
"size":0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 10,
"order": {
"scoreAgg.avg": "desc"
}
},
"aggs":{
"scoreAgg":{
"stats": {
"field": "score"
}
}
}
}
}
}
/**
*桶聚合
*/
@Test
void testAggregation() throws IOException {
//1.准备request
SearchRequest request=new SearchRequest("hotel");
//DSL
request.source().size(0);
//聚合
request.source().aggregation(AggregationBuilders.terms("brandAgg")
.field("brand")
.size(10));
//3发送请求
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
//4.解析结果
System.out.println(response);
//聚合解析
Aggregations aggregations = response.getAggregations();//解析结果
//根据聚合名称获取聚合结果
Terms brandTerms = aggregations.get("brandAgg");
//获取Buckets
List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//遍历
for (Terms.Bucket bucket:buckets){
//获取key
String key = bucket.getKeyAsString();
System.out.println(key);
}
}
多条件聚合:
//多条件聚合
@Test
void contextLoad(){
Map<String, List<String>> result=hotelService.filters();
System.out.println(result);
}
//多参数聚合:品牌、城市、星级聚合
@Override
public Map<String, List<String>> filters() {
try {
//准备Request
SearchRequest request=new SearchRequest("hotel");
//DSL
request.source().size(0);
//聚合
buildAggregations(request);
//3发送请求
SearchResponse response=restHighLevelClient.search(request,RequestOptions.DEFAULT);
//4.解析结果
System.out.println(response);
//聚合解析
Map<String, List<String>> result=new HashMap<>();
Aggregations aggregations = response.getAggregations();//解析结果
List<String> brandList = getAggregationByName(aggregations,"brandAgg");
result.put("品牌",brandList);
List<String> cityList = getAggregationByName(aggregations, "cityAgg");
result.put("城市",cityList);
List<String> starList = getAggregationByName(aggregations, "starAgg");
result.put("星级",starList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//聚合封装
private void buildAggregations(SearchRequest request) {
request.source().aggregation(AggregationBuilders
.terms("brandAgg")
.field("brand")
.size(100));
request.source().aggregation(AggregationBuilders
.terms("cityAgg")
.field("city")
.size(100));
request.source().aggregation(AggregationBuilders
.terms("starAgg")
.field("starName")
.size(100));
}
//封装解析方法
private List<String> getAggregationByName(Aggregations aggregations, String aggName) {
// 4.1.根据聚合名称,获取聚合结果
Terms terms = aggregations.get(aggName);
// 4.2.获取buckets
List<? extends Terms.Bucket> buckets = terms.getBuckets();
// 4.3.遍历
List<String> list = new ArrayList<>(buckets.size());
for (Terms.Bucket bucket : buckets) {
String brandName = bucket.getKeyAsString();
list.add(brandName);
}
return list;
}
查询酒店数据的请求
filters:查询酒店过滤项的请求
他们两个查询携带的参数是一样的
过滤项查询也要带条件,过滤项查询将来需要聚合来实现 ,聚合一旦加了条件,是在限定聚合的范围
发现这两个请求携带的参数是一样的,为什么查过滤项的时候也要带条件呢?过滤项查询要通过聚合来实现,聚合一带上条件就来限定聚合的范围,为何要限定范围呢?直接对整个索引库做聚合不行呢?
在搜索是没有加条件,搜索的是索引库的所有数据,对所有数据做聚合得到城市和品牌没有问题,但是当输入内容虹桥,得到的数据一定是跟上海虹桥有关的结果
上海虹桥有关的城市对应的一定是上海,但是对索引库的所有数据做聚合,得到的城市一定包含所有的城市,所以用户一定就很奇怪拉,命名搜索的是上海的还能出现北京的吗?如果再点击北京在结合搜索条件虹桥,能搜到任何东西吗?肯定是不能的北京没有虹桥,所以说不应该对索引库的所有字段做聚合,用户条件是虹桥,就应该对虹桥相关的酒店做聚合,限定聚合的范围,需要加查询条件,查询时用什么条件聚合时也用什么条件,这样就是在酒店的基础上做聚合,这样查询结果就更精确了因此,在查询过滤项时和查询时要用相同的条件
@PostMapping("filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams params) {
return hotelService.getFilters(params);
}
@Override
public Map<String, List<String>> getFilters(RequestParams params) {
try {
//准备Request
SearchRequest request=new SearchRequest("hotel");
//请求参数 query
buildBasicQuery(params,request);
//DSL
request.source().size(0);
//聚合
buildAggregations(request);
//3发送请求
SearchResponse response=restHighLevelClient.search(request,RequestOptions.DEFAULT);
//4.解析结果
System.out.println(response);
//聚合解析
Map<String, List<String>> result=new HashMap<>(3);
Aggregations aggregations = response.getAggregations();//解析结果
List<String> brandList = getAggregationByName(aggregations,"brandAgg");
result.put("brand",brandList);
List<String> cityList = getAggregationByName(aggregations, "cityAgg");
result.put("city",cityList);
List<String> starList = getAggregationByName(aggregations, "starAgg");
result.put("starName",starList);
return result;
} catch (IOException e) {
throw new RuntimeException(e);
}
}