博客
关于我
ElasticSearch - 基于 DSL 、JavaRestClient 实现数据聚合
阅读量:798 次
发布时间:2023-01-24

本文共 4687 字,大约阅读时间需要 15 分钟。

数据聚合

1.1 基本概念

1.1.1 聚合分类

聚合(aggregations)是对文档数据进行统计分析和运算的重要功能。类似于 MySQL中的聚合函数(如 avg、max 等),Elasticsearch也提供了丰富的聚合功能。

Elasticsearch中的聚合分为三大类,分别是桶(Bucket)聚合、度量(Metric)聚合和管道(Pipeline)聚合。

桶(Bucket)聚合

桶聚合用于对文档进行分组,类似于 MySQL中的 group by 操作。常见的桶聚合类型有:

  • TermAggregation:按照文档字段值(如品牌名称)分组。
  • DataHistogram:按日期阶梯分组(如一天为一组、一周为一组)。

度量(Metric)聚合

度量聚合用于对分组后的文档数据进行计算(如求最大值、最小值、平均值等),与 MySQL中的聚合函数类似。Elasticsearch还提供一个特殊的度量聚合 stats,可以同时计算多个统计指标。

管道(Pipeline)聚合

管道聚合用于对其他聚合的结果进行聚合。例如,先对酒店按品牌分组(桶聚合),然后对每个品牌的酒店价格进行平均值计算(度量聚合),最后再对价格平均值进行排序(度量聚合)。

:管道聚合的使用较少,不是黑马旅游案例的重点。

1.1.2 特点

需要注意的是,参与聚合的字段必须是不可分词的字段(如字符串字段、日期字段、布尔字段等)。因此,日期、数值、布尔类型的字段不能参与聚合。


1.2 DSL 实现 Bucket 聚合

在 Elasticsearch 中,通过 DSL(Domain Specific Language)实现聚合功能。以下是 Bucket 聚合的基本语法和使用场景。

1.2.1 Bucket 聚合基础语法

GET /索引库名/_search {    "size": 0,    "aggs": {        "自定义聚合名": {            "terms": {                "field": "字段名",                "size": 20            }        }    }}
  • 聚合名称:自定义聚合名。
  • 聚合类型terms 表示按字段值分组。
  • 聚合字段:参与聚合的字段。
  • 聚合结果数量size 可设置为具体数字,值超过总数无影响。

示例:按酒店品牌进行分组,字段为 brand

1.2.2 Bucket 聚合结果排序

默认情况下,Bucket 聚合会统计每组文档数量(_count),并根据 _count 降序排序。

示例:按酒店品牌分组,并按照每个品牌的酒店数量进行升序排序。

1.2.3 Bucket 聚合限定范围

默认情况下,Bucket 聚合会对索引库的所有文档进行聚合。可以通过查询条件对聚合范围进行限定,以减少对内存的消耗。

示例:搜索价格 小于等于 200 的酒店,并按品牌分类。


1.3 DSL 实现 Metrics 聚合

度量聚合是对分组后的每组文档数据进行计算。例如,查询每个品牌用户评分的最小值、最大值、平均值等。

1.3.1 度量聚合语法

GET /索引库名/_search {    "size": 0,    "aggs": {        "自定义聚合名": {            "terms": {                "field": "字段名",                "size": 20            },            "aggs": {                "自定义度量聚合": {                    "stats": {                        "field": "score"                    }                }            }        }    }}

步骤

  • 定义聚合名称。
  • terms 聚合按字段值分组。
  • 在分组基础上定义度量聚合(如 stats 聚合)。
  • 示例:按品牌分组,计算每组用户评分的平均值。


    1.4 基于 JavaRestClient 实现聚合

    1.4.1 组装请求

    示例代码

    @Testpublic void testAggregation() throws IOException {    SearchRequest request = new SearchRequest("hotel");    request.source().size(0);    request.source().aggregation(        AggregationBuilders            .terms("brandAgg")            .field("brand")            .size(10));    SearchResponse response = client.search(request, RequestOptions.DEFAULT);    handlerResponse(response);}

    1.4.2 解析响应

    // 解析聚合结果Aggregations aggregations = response.getAggregations();Terms terms = aggregations.get("brandAgg");List
    buckets = terms.getBuckets();for (Bucket bucket : buckets) { String key = bucket.getKeyAsString(); System.out.println(key);}

    1.5 黑马旅游案例

    1.5.1 需求

    通过聚合索引库中的酒店数据,动态生成搜索页面的品牌、城市、星级信息。


    1.5.2 对接前端接口

    请求参数

    {    "brand": ["王国酒店", "大酒店集团"],    "city": ["上海", "北京"],    "starName": [1, 2, 3]}

    响应格式

    {    "城市": ["上海", "北京"],    "品牌": ["王国酒店", "大酒店集团"],    "星级": ["一星级", "二星级", "三星级"]}

    1.5.3 编写 controller

    示例代码

    @RequestMapping("/filters")public Map
    > filters(@RequestBody RequestParams params) { return hotelService.filters(params);}

    1.5.4 添加 filters 接口

    public interface IHotelService extends IService
    { PageResult search(RequestParams params); Map
    > filters(RequestParams params);}

    1.5.5 实现接口

    @Overridepublic Map
    > filters(RequestParams params) { try { SearchRequest request = new SearchRequest("hotel"); handlerBoolQueryBuilder(request, params); request.source().size(0); buildAggregation(request); SearchResponse response = client.search(request, RequestOptions.DEFAULT); Map
    > result = new HashMap<>(); Aggregations aggregations = response.getAggregations(); List
    brandAgg = getAggListByName(aggregations, "brandAgg"); result.put("brand", brandAgg); List
    cityAgg = getAggListByName(aggregations, "cityAgg"); result.put("city", cityAgg); List
    starAgg = getAggListByName(aggregations, "starAgg"); result.put("starName", starAgg); return result; } catch (IOException e) { System.out.println("[HotelService] 酒店数据聚合失败!"); e.printStackTrace(); return null; }}private List
    getAggListByName(Aggregations aggregations, String aggName) { Terms terms = aggregations.get(aggName); List
    buckets = terms.getBuckets(); List
    result = new ArrayList<>(); for (Bucket bucket : buckets) { result.add(bucket.getKeyAsString()); } return result;}private void buildAggregation(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));}

    通过以上方法,可以实现酒店数据的动态聚合,满足前端页面对品牌、城市、星级等字段的实时查询需求。

    转载地址:http://eheyk.baihongyu.com/

    你可能感兴趣的文章
    multiprocessing.Pool:map_async 和 imap 有什么区别?
    查看>>
    MySQL Connector/Net 句柄泄露
    查看>>
    multiprocessor(中)
    查看>>
    mysql CPU使用率过高的一次处理经历
    查看>>
    Multisim中555定时器使用技巧
    查看>>
    MySQL CRUD 数据表基础操作实战
    查看>>
    multisim变压器反馈式_穿过隔离栅供电:认识隔离式直流/ 直流偏置电源
    查看>>
    mysql csv import meets charset
    查看>>
    multivariate_normal TypeError: ufunc ‘add‘ output (typecode ‘O‘) could not be coerced to provided……
    查看>>
    MySQL DBA 数据库优化策略
    查看>>
    multi_index_container
    查看>>
    MySQL DBA 进阶知识详解
    查看>>
    Mura CMS processAsyncObject SQL注入漏洞复现(CVE-2024-32640)
    查看>>
    Mysql DBA 高级运维学习之路-DQL语句之select知识讲解
    查看>>
    mysql deadlock found when trying to get lock暴力解决
    查看>>
    MuseTalk如何生成高质量视频(使用技巧)
    查看>>
    mutiplemap 总结
    查看>>
    MySQL DELETE 表别名问题
    查看>>
    MySQL Error Handling in Stored Procedures---转载
    查看>>
    MVC 区域功能
    查看>>