ES数据聚合

ES聚合常见的有三类:

  • 桶(Bucket):用来对文档做分组

  • TermAggregation:按照文档字段值分组,例如按照品牌值分组、按照城市分组

  • Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组

  • 度量(Metric):用以计算一些值,比如:最大值、最小值、平均值等

  • Avg:求平均值

  • Max:求最大值

  • Min:求最小值

  • Stats:同时求max、min、avg、sum等

  • 管道(pipeline):其它聚合的结果为基础做聚合

注意:参加聚合的字段必须是keyword、日期、数值、布尔类型

    • Bucket聚合语法

现在,我们要统计所有数据中的酒店品牌有几种,此时可以根据酒店品牌的名称做聚合。类型为term类型,DSL示例:

-- 相当于mysql
select brand,count(*) as num from tb_hotel group by brand
GET /hotel/_search
{
  "size": 0,//是不查询原始文档
  "aggs": {//聚合函数AGG
    "brandAgg": {//自己起的名字对品牌的聚合
      "terms": {//根据词条精准查询
        "field": "brand",//查询品牌
        "size": 20,//每页20
        "order": {
          "_count": "asc"//由低到高
        }
      }
    }
  }
}
    • Metric聚合语法

现在我们需要对桶内的酒店做运算,获取每个品牌的用户评分的min、max、avg等值。

这就要用到Metric聚合了,例如stat聚合:就可以获取min、max、avg等结果。

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": { 
      "terms": { 
        "field": "brand", 
        "size": 20
      },
      "aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算
        "scoreAgg": { // 聚合名称
          "stats": { // 聚合类型,这里stats可以计算min、max、avg等
            "field": "score" // 聚合字段,这里是score
          }
        }
      }
    }
  }
}
-- 相当于mysql
select brand,count(*) as num,sum(price),avg(price),max(price),min(price)  from tb_hotel group by brand order by num

知识小结

aggs代表聚合,与query同级,此时query的作用是?

  • 限定聚合的的文档范围

聚合必须的三要素:

  • 聚合名称

  • 聚合类型

  • 聚合字段

聚合可配置属性有:

  • size:指定聚合结果数量

  • order:指定聚合结果排序方式

  • field:指定聚合字段

—————————————————————————————————————

    • API语法

我们以品牌聚合为例,演示下Java的RestClient使用,先看请求组装:

上面的是逻辑,现在开始实操

—————————————————————————————————————

返回值类型是一个Key value类型的 MAP集合Map<String,List<String>>

  • key是字符串,城市、星级、品牌、价格

  • value是集合,例如多个城市的名称

IHotelService

Map<String, List<String>> filters(RequestParams params) throws IOException;
HotelController
@PostMapping("/filters")
public Map<String, List<String>> getFilters(@RequestBody RequestParams params) throws IOException {
    return hotelService.filters(params);
}
HotelService
@Override
public Map<String, List<String>> filters(RequestParams params) throws IOException {
    // 1.创建request
    SearchRequest request = new SearchRequest("hotel");
    // 2.准备DSL参数
    // 2-1 query
    buildBasicQuery(params, request);//此处构建了一个buildBasicQuery方法进行DSL拼接
    // 2-2 设置size
    request.source().size(0);
    // 2-3 聚合//链式编程
    request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(50));
    request.source().aggregation(AggregationBuilders.terms("cityAgg").field("city").size(50));
    request.source().aggregation(AggregationBuilders.terms("starNameAgg").field("starName").size(50));
    // 3.发出请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 4.解析响应
    Map<String, List<String>> result = new HashMap<>();
    Aggregations aggregations = response.getAggregations();
    // 4-1 根据品牌名称
    List<String> brandAgg = getAggByName(aggregations, "brandAgg");
    result.put("brand", brandAgg);
    // 4-2 根据城市名称
    List<String> cityAgg = getAggByName(aggregations, "cityAgg");
    result.put("city", cityAgg);
    // 4-3 根据星级名称
    List<String> starNameAgg = getAggByName(aggregations, "starNameAgg");
    result.put("starName", starNameAgg);

    return result;
}

private List<String> getAggByName(Aggregations aggregations, String aggName) {
    // 根据名称获取聚合结果
    Terms terms = aggregations.get(aggName);
    // 获取bucktes
    List<? extends Terms.Bucket> buckets = terms.getBuckets();
    // 遍历
    List<String> list = new ArrayList<>();
    for (Terms.Bucket bucket : buckets) {
        // 获取聚合名称(key)
        String key = bucket.getKeyAsString();
        // 添加集合
        list.add(key);
    }
    // 返回
    return list;
}

 private void buildBasicQuery(RequestParams params, SearchRequest request) {
        //2-1 query拼接dsl
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //关键字搜索
        String key = params.getKey();
        if (key!=null|| "".equals(key) ){
            boolQuery.must(QueryBuilders.matchAllQuery());
        }else{
            boolQuery.must(QueryBuilders.matchQuery("all",key));
        }
        //城市 过滤
        if (StrUtil.isNotEmpty(params.getCity())){
            boolQuery.filter(QueryBuilders.termQuery("city",params.getCity()));
        }
        //品牌过滤
        if (StrUtil.isNotEmpty(params.getBrand())){
            boolQuery.filter(QueryBuilders.termQuery("brand",params.getBrand()));
        }
        //星级过滤
        if (StrUtil.isNotEmpty(params.getStarName())) {
            boolQuery.filter(QueryBuilders.termQuery("starName",params.getStarName()));
        }
        //价格区间
        if (params.getMinPrice()!=null&&params.getMaxPrice()!=null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(params.getMinPrice()).lte(params.getMaxPrice()));
        }
        //2.算分控制
        FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery(boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        QueryBuilders.termQuery("isAD", true),
                        ScoreFunctionBuilders.weightFactorFunction(10)
                )
        });
        // 3.放入 source
        request.source().query(functionScoreQuery);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值