ES聚合分析

1.metric(指标)聚合

1.1 单值分析

  • min 求指定字段的最小值

    # 求价格的最小值
    {
    "size":0,
    "aggs":{
    "min_price":{
    "min":{
    "field":"price"
    }
    }
    }
    }
  • max 求指定字段的最大值

    # 求价格的最大值
    {
    "size":0,
    "aggs":{
    "max_price":{
    "max":{
    "field":"price"
    }
    }
    }
    }
  • avg 求指定字段的平均值

    # 求价格的平均值
    {
    "size":0,
    "aggs":{
    "avg_price":{
    "avg":{
    "field":"price"
    }
    }
    }
    }
  • sum 求指定字段的总和

    # 求价格的总和
    {
    "size":0,
    "aggs":{
    "sum_price":{
    "sum":{
    "field":"price"
    }
    }
    }
    }
  • value_count 统计某字段有值的文档数

    # 求price有值的个数
    {
    "aggs":{
    "price_count":{
    "value_count":{
    "field":"price"
    }
    }
    }
    }
  • cardinality 去重计数

    #查询有多少种job(不分词下进行去重)
    {
    "aggs":{
    "job_count":{
    "cardinality":{
    "field":"job.keyword"
    }
    }
    }
    }

1.2 多值分析

  • stats 包含多种返回结果:min,max,avg,sum,count

    # 可以分析查询出以上的所有关于价格的单值结果
    {
    "aggs":{
    "price_stats":{
    "stats":{
    "field":"price"
    }
    }
    }
    }
  • Extended stats 高级统计,比stats查询多四个结果:平方和、方差、标准差、平均值加/减两个标准差的区间

    {
    "aggs":{
    "extended_salary":{
    "extended_stats":{
    "field":"salary"
    }
    }
    }
    }
  • Percentiles:占比百分位数统计

    # 统计salay每个值所在的百分比
    {
    "aggs":{
    "percentiles_salary":{
    "percentiles":{
    "field":"salary"
    }
    }
    }
    } # 统计指定分位值的数据是多少
    {
    "aggs":{
    "percentiles_salary":{
    "percentiles":{
    "field":"salary",
    "percents" : [75, 99, 99.9]
    }
    }
    }
    }
  • Percentiles rank 统计值小于等于指定值的文档占比

    {
    "aggs":{
    "gge_perc_rank":{
    "percentile_ranks":{
    "field":"price",
    "values":[
    100,
    200
    ]
    }
    }
    }
    }
  • top_hits:用于分桶后获取该桶内最匹配的顶部文档列表,即详情数据

    {
    "aggs":{
    "jobs":{
    "terms":{
    "field":"job.keyword",
    "size":10
    },
    "aggs":{
    "top_jobs":{
    "top_hits":{
    "size":10,
    "sort":[
    {
    "age":{
    "order":"desc"
    }
    }
    ]
    }
    }
    }
    }
    }
    }

2.bucket(桶)聚合

2.1 Bucket的分桶策略

  • Terms:按照指定字段进行分桶

    {
    "size":0,
    "aggs":{
    "terms_jobs":{
    "terms":{
    "field":"job.keyword",
    "size":5
    }
    }
    }
    }
  • Range:按照指定字段的值的范围进行分桶

    {
    "size":0,
    "aggs":{
    "group_by_price":{
    "range":{
    "field":"price",
    "ranges":[
    {
    "key":"<200",
    "to":200
    },
    {
    "from":200,
    "to":400
    },
    {
    "key":">400",
    "from":400
    }
    ]
    }
    }
    }
    }
  • Date_Range:按照日期字段的日期范围进行分桶

    {
    "size":0,
    "aggs":{
    "group_by_birth":{
    "date_range":{
    "field":"birth",
    "format":"yyyy",
    "ranges":[
    {
    "key":"2000年以前",
    "to":"2000"
    },
    {
    "key":"2000年 - 2020年",
    "from":"2000",
    "to":"2020"
    },
    {
    "key":"2020年以后",
    "from":"2020"
    }
    ]
    }
    }
    }
    }
  • Histogram:直方图,以固定间隔的策略来分割数据

    {
    "size":0,
    "aggs":{
    "salary_hist":{
    "histogram":{
    "field":"salary",
    "interval":5000,
    "extended_bounds":{
    "min":0,
    "max":40000
    }
    }
    }
    }
    }
  • Date_Histogram:针对日期的直方图或柱状图,时序数据分析常用的。

    {
    "size":0,
    "aggs":{
    "by_year":{
    "date_histogram":{
    "field":"birth",
    "interval":"year",
    "format":"yyyy"
    }
    }
    }
    }

2.2 Bucket + Metric

  • 案例一:按照不同年龄段分桶,求每个年龄段的工资平均值

    {
    "size":0,
    "aggs":{
    "group_by_age":{
    "range":{
    "field":"age",
    "ranges":[
    {
    "key":"<20",
    "to":20
    },
    {
    "key":"20 - 50",
    "from":20,
    "to":50
    },
    {
    "key":">50",
    "from":50
    }
    ]
    },
    "aggs":{
    "avg_salary":{
    "avg":{
    "field":"salary"
    }
    }
    }
    }
    }
    }
  • 案例二:分桶再分桶:先根据job分桶,再按照不同年龄划分

    {
    "size":0,
    "aggs":{
    "group_by_job":{
    "terms":{
    "field":"job",
    "size":10
    },
    "aggs":{
    "range_age":{
    "range":{
    "field":"age",
    "ranges":[
    {
    "key":"<20",
    "to":20
    },
    {
    "key":"20 - 50",
    "from":20,
    "to":50
    },
    {
    "key":">50",
    "from":50
    }
    ]
    }
    }
    }
    }
    }
    }
  • 案例三:分桶后进行数据分析

    # 求出不同种工作的平均薪资
    {
    "size":0,
    "aggs":{
    "group_by_job":{
    "terms":{
    "field":"job",
    "size":10
    },
    "aggs":{
    "avg_salary":{
    "stats":{
    "field":"salary"
    }
    }
    }
    }
    }
    }

3.pipeline(管道)聚合

3.1 Parent结果内嵌到现有的聚合分析结果中

  • Derivative(导数)
  • Moving Average(移动平均)
  • Cumulative Sum(累计求和)

案例一:根据生日按月分组,求出每组的平均值,以及导数

{
"size":0,
"aggs":{
"group_by_birth":{
"date_histogram":{
"field":"birth",
"interval":"mounth",
"format":"yyyy"
},
"aggs":{
"avg_salary":{
"avg":{
"field":"salary"
}
},
"derivative_avg_salary":{
"derivative":{
"buckets_path":"avg_salary"
}
}
}
}
}
}

3.2 Sibing结果与现有聚合分析结果同级

  • Max/Min/Avg/Sum Bucket
  • Stats/Extended Stats Bucket
  • Percentiles Bucket

案例一:根据job进行分组,求出每组的平均工资,找出这些组平均工资的最小值

{
"size":0,
"aggs":{
"group_by_job":{
"terms":{
"field":"job",
"size":10
},
"aggs":{
"avg_salary":{
"avg":{
"field":"salary"
}
}
}
},
"min_salary_by_job":{
"min_bucket":{
"buckets_path":"group_by_job>avg_salary"
}
}
}
}

4.ES中的Java API

4.1 terms,range,date_range等聚合的演示

  • ES相关依赖

    <dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.3.2</version>
    </dependency>
    <dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>transport</artifactId>
    <version>7.3.2</version>
    </dependency>
    <dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.3.2</version>
    </dependency>
    <!-- Java High Level REST Client -->
    <dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.3.2</version>
    </dependency>
  • ES相关聚合部分的演示代码

    package com.lenovo.btit.elasticsearch;
    import org.apache.commons.lang3.StringUtils;
    import org.elasticsearch.action.search.SearchRequest;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.search.aggregations.AggregationBuilders;
    import org.elasticsearch.search.aggregations.bucket.range.DateRangeAggregationBuilder;
    import org.elasticsearch.search.aggregations.bucket.range.Range;
    import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
    import org.elasticsearch.search.aggregations.bucket.terms.Terms;
    import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
    import org.elasticsearch.search.aggregations.metrics.Avg;
    import org.elasticsearch.search.builder.SearchSourceBuilder; import java.io.IOException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map; /**
    * Es聚合分析使用
    *
    * @author: zangchuanlei
    * @date: 2021/7/11
    * @time: 15:18
    */
    public class EsServiceBucket { private RestHighLevelClient highLevelClient;
    // terms某个字段进行分组标识
    private final String BUCKET_TERMS = "1";
    // range按照某个范围进行分组(double,int)
    private final String BUCKET_RANGE = "2";
    // date_range按照时间范围进行分组
    private final String BUCKET_DATA_RANGE = "3"; /**
    * @param bucketType 桶聚合类型
    * @param resultName 结果集名称
    * @param size 每页几个数据
    * @param indices 文档库名
    * @description 执行ES聚合分析查询
    * @author zangchuanlei
    * @date 2021/7/11 16:15
    */
    private Map<String, Long> query(String bucketType, String resultName, int size, String... indices) {
    // 获取搜索构建器
    SearchSourceBuilder sourceBuilder;
    switch (bucketType) {
    case BUCKET_TERMS:
    sourceBuilder = getSourceBuilderOfTerms(resultName, size);
    break;
    case BUCKET_RANGE:
    sourceBuilder = getSourceBuilderOfRange(resultName, size);
    break;
    case BUCKET_DATA_RANGE:
    sourceBuilder = getSourceBuilderOfDataRange(resultName, size);
    break;
    default:
    sourceBuilder = new SearchSourceBuilder();
    break;
    } //建立关于指定文档库的搜索请求
    SearchRequest searchRequest = new SearchRequest()
    .indices(indices)
    .source(sourceBuilder); //返回处理结果
    return getResultMapByBucket(bucketType,searchRequest, resultName);
    } /**
    * @param searchRequest 搜索请求
    * @param resultName 结果集名称
    * @description 处理搜索响应数据
    * @author zangchuanlei
    * @date 2021/7/11 16:41
    */
    private Map<String, Long> getResultMapByBucket(String bucketType, SearchRequest searchRequest, String resultName) {
    // 创建返回结果map容器
    Map<String, Long> rtnMap = new HashMap<>();
    try {
    SearchResponse searchResponse = highLevelClient.search(searchRequest, RequestOptions.DEFAULT); // 字段分组
    if (StringUtils.equals(BUCKET_TERMS, bucketType)) {
    // 根据结果集名称获取Terms
    Terms aggsTerm = searchResponse.getAggregations().get(resultName);
    //获得分组后的桶信息
    List<? extends Terms.Bucket> termBuckets = aggsTerm.getBuckets();
    termBuckets.forEach(b -> {
    rtnMap.put(b.getKeyAsString(), b.getDocCount());
    System.out.println("key:" + b.getKeyAsString());
    System.out.println("count:" + b.getDocCount());
    // 处理子聚合,打印每组的平均价格
    Avg averageBalance = b.getAggregations().get("price_avg");
    System.out.println("key = "+b.getKeyAsString()+"的价格平均值为:"+averageBalance.getValue());
    }); // 范围分组
    } else if (StringUtils.equals(BUCKET_RANGE, bucketType) ||
    StringUtils.equals(BUCKET_DATA_RANGE, bucketType)) {
    Range aggsRange = searchResponse.getAggregations().get(resultName);
    List<? extends Range.Bucket> rangeBuckets = aggsRange.getBuckets();
    rangeBuckets.forEach(b->{
    rtnMap.put(b.getKeyAsString(), b.getDocCount());
    });
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    return rtnMap;
    } /**
    * @param resultName 结果集名称
    * @param size 显示个数
    * @description 构建根据商品品牌分组,并计算每组的价格平均值
    * @author zangchuanlei
    * @date 2021/7/11 16:24
    */
    private SearchSourceBuilder getSourceBuilderOfTerms(String resultName, int size) {
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // step1:先根据品牌进行分组
    TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms(resultName)
    .field("bank.keyword"); // step2:计算每个品牌的的平均价格
    aggregationBuilder.subAggregation(AggregationBuilders.avg("price_avg").field("price")); sourceBuilder.aggregation(aggregationBuilder);
    sourceBuilder.size(size).trackTotalHits(true);
    return sourceBuilder;
    } /**
    * @param resultName 结果集名称
    * @param size 显示个数
    * @description 构建根据商品价格范围分组的聚合查询条件
    * @author zangchuanlei
    * @date 2021/7/11 16:52
    */
    private SearchSourceBuilder getSourceBuilderOfRange(String resultName, int size) {
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    RangeAggregationBuilder aggregationBuilder = AggregationBuilders.range(resultName)
    .field("price")
    // 分组范围:小于1000,1000-3000,大于3000
    .addUnboundedTo(1000).addRange(1000, 3000).addUnboundedFrom(3000);
    sourceBuilder.aggregation(aggregationBuilder);
    sourceBuilder.size(size).trackTotalHits(true);
    return sourceBuilder;
    } /**
    * @param resultName
    * @param size
    * @description 构建根据上市时间范围分组的聚合查询条件
    * @author zangchuanlei
    * @date 2021/7/11 17:05
    */
    private SearchSourceBuilder getSourceBuilderOfDataRange(String resultName, int size) {
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    // 按照上市时间进行分组
    DateRangeAggregationBuilder aggregationBuilder = AggregationBuilders.dateRange(resultName).format("yyyy-MM-dd")
    .field("launch_date")
    .addUnboundedTo("2000-01-01以前", "2000-01-01")
    .addRange("2000-01-01至2010-12-31", "2000-01-01", "2010-12-31")
    .addUnboundedFrom("2010-12-31以后", "2010-12-31"); sourceBuilder.aggregation(aggregationBuilder);
    sourceBuilder.size(size).trackTotalHits(true);
    return sourceBuilder;
    }
    }

面试官问我会ES么,我说不会,抓紧学起【ES(一)聚合分析篇】的更多相关文章

  1. 面试官问我会不会Elasticsearch,我语塞了...

    少点代码,多点头发 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 从今天开始准备给大家带来全新 ...

  2. 「干货」面试官问我如何快速搜索10万个矩形?——我说RBush

    「干货」面试官问我如何快速搜索10万个矩形?--我说RBUSH 前言 亲爱的coder们,我又来了,一个喜欢图形的程序员‍,前几篇文章一直都在教大家怎么画地图.画折线图.画烟花,难道图形就是这样嘛,当 ...

  3. 每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

    面试结束时面试官问"你有什么问题需要问我呢",该如何回答?

  4. 面试官问我,Redis分布式锁如何续期?懵了。

    前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...

  5. 面试官问,说一个你在工作非常有价值的bug

    如果你去参考面试,做足了准备,面对面试官员从容不迫,吐沫横飞的大谈自己的工作经历.突然,面试官横插一句:说一个你在工作非常有价值的bug.顿时,整个空气都仿佛都凝固了!“What?”... 我想没几个 ...

  6. 面试官问:JS的this指向

    前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实.读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论 ...

  7. 当面试官问你sql优化的时候。。。

    当面试官问你有关sql优化的问题时,直接拿笔写给他: 8-select 9-distinct<column_list> 1-from left_table 3-<join_type& ...

  8. 面试官问你JS基本类型时他想知道什么?

    面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...

  9. 面试官问线程安全的List,看完再也不怕了!

    最近在Java技术栈知识星球里面有球友问到了线程安全的 List: 扫码查看答案或加入知识星球 栈长在之前的文章<出场率比较高的一道多线程安全面试题>里面讲过 ArrayList 的不安全 ...

  10. 美团面试官问我一个字符的String.length()是多少,我说是1,面试官说你回去好好学一下吧

    本文首发于微信公众号:程序员乔戈里 public class testT { public static void main(String [] args){ String A = "hi你 ...

随机推荐

  1. 【3】opencv_contrib 4.3.0库配置+opencv安装

    相关文章: [1]windows下安装OpenCV(4.3)+VS2017安装+opencv_contrib4.3.0配置 [2]Visual Studio 2017同时配置OpenCV2.4 以及O ...

  2. C# 通过VMI接口获取硬件ID

    使用C#语言实现通过VMI(虚拟机监控器)接口来获取硬件ID的过程.VMI是一种用于虚拟化环境的接口,用于管理虚拟机和宿主机之间的通信和资源共享.具体实现中,需要通过添加System.Manageme ...

  3. LoopAndLoop【安卓逆向】

    LoopAndLoop(阿里CTF) 首先是通用步骤 解压附件后发现是APK文件,打开jeb进行反编译,反编译结果如下: 可以看到程序自定了几个check函数,并且调用了自定义库"lhm&q ...

  4. 架构设计脱胎换骨!英特尔酷睿Ultra深度解析

    英特尔正式发布了第一代酷睿Ultra处理器平台,也就是首个基于Intel 4制程工艺(7nm)打造的移动级处理器平台,其核心代号为Meteor Lake,产品系列贴标设计也采用了全新方案. 同时在命名 ...

  5. 【Linux】root密码忘记了怎么办【技能篇】一分钟教会你重置root密码

    [Linux]root密码重置 文章目录 前言介绍 操作步骤 尾声 前言介绍 那么这里博主先安利一下一些干货满满的专栏啦! 数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是 ...

  6. DBGRIDEH 底部多列 发现

    1.设置底部行数 2.点击footers 单独对每一行进行设置 3.单独对这两行 进行设置 5.看下辅助 所以用的时候可以这样用:WeiTopTradeShow.FieldColumns['top_x ...

  7. Linux sed输出文件内容的某几行

    命令: sed -n "开始行,结束行p" 文件名 sed -n '70,75p'   文件名             # 输出第70行到第75行的内容 sed -n '6p;26 ...

  8. CF1902

    A 只要不是全 \(1\) 即可. B 二分完成天数. C \(x\) 取差的 \(gcd\),\(a_{n+1}\) 见缝插针. D 用一个 map 记录按原始操作序列,要走到 \((x,y)\) ...

  9. VMware 虚拟机一键去虚拟化工具

    前言: 如果你想在 VMware 虚拟机里面多开玩游戏的话,但是现在大多数网游都会检测是否虚拟机,进入游戏被检测到在虚拟机中运行,游戏可能直接闪退.所以就得对 VMware 虚拟机进行去除虚拟化. 原 ...

  10. 【React】排查两小时,修改一个词,记一个因代码书写不规范导致的生命周期BUG

    壹 ❀ 引 因为现在工作主要以修bug为主,日常工作中总是会接触到千奇百怪的前端问题,它可能是代码缺陷导致的程序错误,也可能是方案不合理造成的性能问题,老实说修bug是一件很枯燥的事情,你需要阅读大量 ...