数据聚合、

数据聚合

聚合(Aggregations):可以实现对文档数据的统计、分析、运算。

常见的聚合有三类:

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

​ TermAggtegation:按照文档字段值分组

​ Date Histogram:按照日期阶梯分组

  • 度量(Metric)聚合:

​ Avg:求平均值

​ Max:求最大值

​ Min:求最小值

​ Status:同时求max、min、avg、sum等

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

    具体可查阅官方文档[Aggregations | Elasticsearch Guide 8.3] | Elastic

DSL实现Bucket聚合

按照品牌名聚合

#聚合功能
GET /hotel/_search
{
  "size":0,         #设置size为0,结果中不包含文档,只包含聚合结果
  "aggs": {
    "brandAgg": {    #给聚合起的名字
      "terms": {
        "field": "brand",
        "size": 10      #希望获取的聚合结果的数量
      }
    }
  }
}


默认情况下,Bucker聚合会统计Bucket内文档的数量,记为_count,并按照__count降序排序

#聚合功能
GET /hotel/_search
{
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 10,
        "order": {
          "_count": "asc"
        }
      }
    }
  }
}

限定聚合范围

只要添加query条件即可

#聚合功能
GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "lte": 200
      }
    }
  }, 
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 10,
        "order": {
          "_count": "asc"
        }
      }
    }
  }
}

聚合必须的三要素:

  • 聚合名称
  • 聚合类型
  • 聚合字段

聚合可配置的属性有:

  • size:指定聚合结果数量
  • order:指定聚合结果排序方式
  • field:指定聚合字

DSL实现Metrics聚合

取每个品牌的用户评分的min,max,avg

#嵌套聚合metric

GET /hotel/_search
{
  
  "size":0,
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20
      },
      "aggs": {
        "scoreAgg": {
        "stats": {
          "field": "score"
        }
        }
      }
    }
  }
}

数据聚合、_第1张图片

对平均分进行排序

#嵌套聚合metric

GET /hotel/_search
{
  
  "size":0,
  "aggs": {   
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20,
        "order": {
          "scoreAgg.avg": "desc"
        }
      },
      "aggs": {
        "scoreAgg": {
        "stats": {
          "field": "score"
        }
        }
      }
    }
  }
}

RestAPI实现聚合

  @Test
void testAgg() throws IOException {
        //准备request
        SearchRequest request=new SearchRequest("hotel");
        //准备dsl
        request.source().size(0);
        request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(10));

        //发送请求
        SearchResponse search = client.search(request, RequestOptions.DEFAULT);

        //对结果处理
        Aggregations aggregations = search.getAggregations();
        //注意是Terms
        Terms brandAgg = aggregations.get("brandAgg");
        List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();
        //遍历
        for (Terms.Bucket bucket : buckets) {
            String keyAsString = bucket.getKeyAsString();
            System.out.println(keyAsString);
        }


    }

案例:在IUserService中定义方法,实现对品牌、城市、星级的聚合

  @Override
    public Map> agg(RequestParams params) {
        try {
            //获取过滤条件
            //准备request
        SearchRequest request=new SearchRequest("hotel");
        
        //这一部分可以封装为一个函数
      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));

        boolQuery(params,request);


        SearchResponse search = client.search(request, RequestOptions.DEFAULT);

        Aggregations aggregations = search.getAggregations();
        Terms brandAgg = aggregations.get("brandAgg");
        Terms cityAgg = aggregations.get("cityAgg");
        Terms starAgg = aggregations.get("starAgg");

        List buckets = brandAgg.getBuckets();
        List buckets1 = cityAgg.getBuckets();
        List buckets2 = starAgg.getBuckets();
        List list=new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            String keyAsString = bucket.getKeyAsString();
            list.add(keyAsString);
        }

        Map> map=new HashMap<>();
        map.put("brand",list);

        List list1=new ArrayList<>();
        for (Terms.Bucket bucket : buckets1) {
            String keyAsString = bucket.getKeyAsString();
            list1.add(keyAsString);
        }
        map.put("city",list1);

        List list2=new ArrayList<>();
        for (Terms.Bucket bucket : buckets2) {
            String keyAsString = bucket.getKeyAsString();
            list2.add(keyAsString);
        }
        map.put("starName",list2);

        return map;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

测试这个方法

@SpringBootTest
class HotelDemoApplicationTests {
@Autowired
private HotelService hotelService;
    @Test
    void contextLoads() {
        Map<String, List<String>> filters = hotelService.filters();
        System.out.println(filters);
    }

}

数据聚合、_第2张图片

实现前端的过滤效果

数据聚合、_第3张图片

在IHotelService接口中定义过滤的方法

Map> filters (RequestParams params);

在上面的代码新增参数params

其中的boolQuery()就是查询实现的过滤

 private static void boolQuery(RequestParams params, SearchRequest request) {
        String key = params.getKey();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (key ==null||"".equals(key)){
        //key为空,直接查询所有
//            request.source().query(QueryBuilders.matchAllQuery());
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
    }
    else{
//            request.source().query(QueryBuilders.matchQuery("all",key));
            boolQueryBuilder.must(QueryBuilders.matchQuery("all", key));
    }

        //城市
        if (params.getCity()!=null&&!"".equals(params.getCity())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        //星级
        if (params.getStarName()!=null&&!"".equals(params.getStarName())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("starName", params.getStarName()));

        }
        //品牌

        if (params.getBrand()!=null&&!"".equals(params.getBrand())){
            boolQueryBuilder.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        //价格范围
        if (params.getMinPrice()!=null&& params.getMaxPrice()!=null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(params.getMaxPrice()).gte(params.getMinPrice()));
        }

        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder,new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("isAD",true),ScoreFunctionBuilders.weightFactorFunction(10))
        });


        request.source().query(functionScoreQueryBuilder);
    }

你可能感兴趣的:(微服务,elasticsearch,搜索引擎)