当前位置: 首页 > news >正文

ElasticSearch的DSL查询⑤(ES数据聚合、DSL语法数据聚合、RestClient数据聚合)

目录

一、数据聚合

1.1 DSL实现聚合

1.1.1 Bucket聚合 

1.1.2 带条件聚合

1.1.3 Metric聚合

1.1.4 总结

2.1 RestClient实现聚合

2.1.1 Bucket聚合

2.1.2 带条件聚合

2.2.3 Metric聚合


一、数据聚合

聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如:

  • 什么品牌的手机最受欢迎?

  • 这些手机的平均价格、最高价格、最低价格?

  • 这些手机每月的销售情况如何?

ES实现这些统计功能比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效果。

聚合常见的有三类:

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

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

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

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

    • Avg:求平均值

    • Max:求最大值

    • Min:求最小值

    • Stats:同时求maxminavgsum

  • 管道(pipeline)聚合:将其它聚合的结果为基础做进一步做深层次的运算(聚合)

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

1.1 DSL实现聚合

与之前的搜索功能类似,我们依然先学习DSL的语法,再学习JavaAPI. 

1.1.1 Bucket聚合 

例如我们要统计所有商品中共有哪些商品分类,其实就是以分类(category)字段对数据分组。category值一样的放在同一组,属于Bucket聚合中的Term聚合。 

基本语法如下: 

# 聚合
GET /goods/_search
{"query": {"match_all": {}}, // 当没有条件(查询所有)的时候可以省略"aggs": { // 定义聚合"cate_agg": { // 给聚合起个名字,随意"terms": { // 聚合类型,terms:词条类型的"field": "category", // 参与聚合的字段"size": 20 // 希望获取聚合结果的数量,默认20}}},"size":0 //在查询过程中不仅仅会把聚合结果返回给我们,同时还会把搜索结果的数据返回给我们,设置size为0,就是不需要返回文档信息。如果不设置size默认为10
}

语法说明:

  • size:在查询过程中不仅仅会把聚合结果返回给我们,同时还会把搜索结果的数据返回给我们,设置size为0,就是不需要返回文档信息。如果不设置size默认为10

  • aggs:定义聚合

    • cate_agg:聚合名称,自定义,但不能重复

      • terms:聚合的类型,按分类聚合,所以用term

        • field:参与聚合的字段名称

        • size:希望返回的聚合结果的最大数量

查询的结果: 

这个就有点类始于Sql语句:select  category,count(*)  from goods group by category

一次可以获取多个聚合:

1.1.2 带条件聚合

默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可。

例如,查询价格高于1000元的手机品牌有哪些

我们需要从需求中分析出搜索查询的条件和聚合的目标:

  • 搜索查询条件:

    • 价格高于1000

    • 必须是手机

  • 聚合目标:统计的是品牌,肯定是对brand字段做term聚合

语法如下:

# 聚合
GET /goods/_search
{"query": {"bool": {"filter": [{"term": {"category": "手机"}},{"range": {"price": {"gt": 1000}}}]}},"aggs": {"brand_agg":{"terms": {"field": "brand","size": 20}}},"size":0 
}

聚合结果如下:

可以看到,结果中只剩下1个品牌了。。。

1.1.3 Metric聚合

除了对数据分组(Bucket)以外,我们还可以对每个Bucket内的数据进一步做数据计算和统计。

例如:想知道手机有哪些品牌,每个品牌的价格最小值、最大值、平均值。

语法如下:

# 聚合
GET /goods/_search
{"query": {"bool": {"filter": [{"term": {"category": "手机"}}]}},"aggs": {"brand_agg":{"terms": {"field": "brand","size": 20},"aggs": { // 对品牌分组的结果再进行聚合"price_stats": { // 聚合名称随意"stats": { // 聚合类型:Avg:求平均值,Max:求最大值,Min:求最小值,Stats:同时求max、min、avg、sum。"field": "price" // 要聚合字段}}}}},"size":0 
}

可以看到我们在brand_agg聚合的内部,我们新加了一个aggs参数。这个聚合就是brand_agg的子聚合,会对brand_agg形成的每个桶中的文档分别统计。

  • price_stats:聚合名称

    • stats:聚合类型,stats是metric聚合的一种

      • field:聚合字段,这里选择price,统计价格

由于stats是对brand_agg形成的每个品牌桶内文档分别做统计,因此每个品牌都会统计出自己的价格最小、最大、平均值。 

结果如下:

另外,我们还可以让聚合按照每个品牌的价格平均值排序: 

1.1.4 总结

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

  • 限定聚合的的文档范围

聚合必须的三要素:

  • 聚合名称

  • 聚合类型

  • 聚合字段

聚合可配置属性有:

  • size:指定聚合结果数量

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

  • field:指定聚合字段 

2.1 RestClient实现聚合

        可以看到在DSL中,aggs聚合条件与query条件是同一级别,都属于查询JSON参数。因此依然是利用request.source()方法来设置。不过聚合条件的要利用AggregationBuilders这个工具类来构造。

2.1.1 Bucket聚合

DSL与JavaAPI的语法对比如下:

聚合结果解析对比:

完整代码:

    @Testpublic void testAgg() throws IOException {// 1.创建Request对象SearchRequest request = new SearchRequest("goods");// 2.准备请求参数request.source().size(0);// 2.1 聚合参数request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(5));// 3.发送请求SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);// 4.解析聚合结果Aggregations aggregations = response.getAggregations();// 4.1 获取品牌聚合Terms brandAgg = aggregations.get("brandAgg");// 4.2 获取聚合中的桶List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();// 4.3 遍历桶内数据for (Terms.Bucket bucket : buckets) {// 4.4 获取桶内keySystem.out.println("key = " + bucket.getKeyAsString());System.out.println("count = " + bucket.getDocCount());}}

执行结果:

2.1.2 带条件聚合

例如,查询价格高于1000元的手机品牌有哪些

DSL与JavaAPI的语法对比如下:

Java代码如下:

    @Testpublic void testConditionAgg() throws IOException {// 1.创建Request对象SearchRequest request = new SearchRequest("goods");// 2.准备请求参数BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("category", "手机")).filter(QueryBuilders.rangeQuery("price").gt(1000));request.source().query(boolQueryBuilder);request.source().size(0);// 2.1 聚合参数request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(5));// 3.发送请求SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);// 4.解析聚合结果Aggregations aggregations = response.getAggregations();// 4.1 获取品牌聚合Terms brandAgg = aggregations.get("brandAgg");// 4.2 获取聚合中的桶List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();// 4.3 遍历桶内数据for (Terms.Bucket bucket : buckets) {// 4.4 获取桶内keySystem.out.println("key = " + bucket.getKeyAsString());System.out.println("count = " + bucket.getDocCount());}}

执行结果:

可以看到,结果中只剩下1个品牌了。。。

2.2.3 Metric聚合

例如:想知道手机有哪些品牌,每个品牌的价格最小值、最大值、平均值。

DSL与JavaAPI的语法对比如下:

结果解析对比:

完整代码如下:

    @Testpublic void testAgg() throws IOException {// 1.创建Request对象SearchRequest request = new SearchRequest("goods");// 2.准备请求参数BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("category", "手机"));request.source().query(boolQueryBuilder);request.source().size(0);// 2.1 聚合参数request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(5).order(// 排序,true:升序(asc),false:降序(desc)BucketOrder.aggregation("priceStats.avg", false) ).subAggregation(AggregationBuilders.stats("priceStats").field("price")));// 3.发送请求SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);// 4.解析聚合结果Aggregations aggregations = response.getAggregations();// 4.1 获取品牌聚合Terms brandAgg = aggregations.get("brandAgg");// 4.2 获取聚合中的桶List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();// 4.3 遍历桶内数据for (Terms.Bucket bucket : buckets) {// 4.4 获取桶内keySystem.out.println("key = " + bucket.getKeyAsString());System.out.println("count = " + bucket.getDocCount());Aggregations subAgg = bucket.getAggregations();Stats priceStats = subAgg.get("priceStats");System.out.println("min = " + priceStats.getMin());System.out.println("max = " + priceStats.getMax());System.out.println("avg = " + priceStats.getAvg());System.out.println("sum = " + priceStats.getSum());}}

执行结果:

 

感谢大家的阅读

http://www.lryc.cn/news/432984.html

相关文章:

  • DBeaver 24.0 高阶用法
  • 外卖会员卡项目骗局揭秘,你还在做梦吗?改醒醒了
  • 比较顺序3s1,3s2,4s1之间的关系
  • BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin
  • 数据库锁之行级锁、记录锁、间隙锁和临键锁
  • 基于yolov8的血细胞检测计数系统python源码+onnx模型+评估指标曲线+精美GUI界面
  • 【深度学习详解】Task3 实践方法论-分类任务实践 Datawhale X 李宏毅苹果书 AI夏令营
  • 乐凡北斗 | 手持北斗智能终端的作用与应用场景
  • Linux:线程互斥
  • misc流量分析
  • Linux驱动(五):Linux2.6驱动编写之设备树
  • 算法【Java】 —— 前缀和
  • python网络爬虫(四)——实战练习
  • tio websocket 客户端 java 代码 工具类
  • 通过卷积神经网络(CNN)识别和预测手写数字
  • 【A题第二套完整论文已出】2024数模国赛A题第二套完整论文+可运行代码参考(无偿分享)
  • 一份热乎的数据分析(数仓)面试题 | 每天一点点,收获不止一点
  • 3 html5之css新选择器和属性
  • 【Kubernetes】K8s 的鉴权管理(一):基于角色的访问控制(RBAC 鉴权)
  • 保研 比赛 利器: 用AI比赛助手降维打击数学建模
  • 秋招校招,在线性格测评应该如何应对
  • chrome 插件开发入门
  • 揭开面纱--机器学习
  • Python中的私有属性与方法:解锁面向对象编程的秘密
  • 开篇_____何谓安卓机型“工程固件” 与其他固件的区别 作用
  • DBeaver 连接 MySQL 报错 Public Key Retrieval is not allowed
  • 三个月涨粉两万,只因为知道了这个AI神器
  • vulhub GhostScript 沙箱绕过(CVE-2018-16509)
  • 李宏毅机器学习笔记——反向传播算法
  • 内推|京东|后端开发|运维|算法...|北京 更多岗位扫内推码了解,直接投递,跟踪进度