面试官问我会ES么,我说不会,抓紧学起【ES(一)聚合分析篇】
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(一)聚合分析篇】的更多相关文章
- 面试官问我会不会Elasticsearch,我语塞了...
少点代码,多点头发 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles 从今天开始准备给大家带来全新 ...
- 「干货」面试官问我如何快速搜索10万个矩形?——我说RBush
「干货」面试官问我如何快速搜索10万个矩形?--我说RBUSH 前言 亲爱的coder们,我又来了,一个喜欢图形的程序员,前几篇文章一直都在教大家怎么画地图.画折线图.画烟花,难道图形就是这样嘛,当 ...
- 每日一问:面试结束时面试官问"你有什么问题需要问我呢",该如何回答?
面试结束时面试官问"你有什么问题需要问我呢",该如何回答?
- 面试官问我,Redis分布式锁如何续期?懵了。
前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...
- 面试官问,说一个你在工作非常有价值的bug
如果你去参考面试,做足了准备,面对面试官员从容不迫,吐沫横飞的大谈自己的工作经历.突然,面试官横插一句:说一个你在工作非常有价值的bug.顿时,整个空气都仿佛都凝固了!“What?”... 我想没几个 ...
- 面试官问:JS的this指向
前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实.读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论 ...
- 当面试官问你sql优化的时候。。。
当面试官问你有关sql优化的问题时,直接拿笔写给他: 8-select 9-distinct<column_list> 1-from left_table 3-<join_type& ...
- 面试官问你JS基本类型时他想知道什么?
面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...
- 面试官问线程安全的List,看完再也不怕了!
最近在Java技术栈知识星球里面有球友问到了线程安全的 List: 扫码查看答案或加入知识星球 栈长在之前的文章<出场率比较高的一道多线程安全面试题>里面讲过 ArrayList 的不安全 ...
- 美团面试官问我一个字符的String.length()是多少,我说是1,面试官说你回去好好学一下吧
本文首发于微信公众号:程序员乔戈里 public class testT { public static void main(String [] args){ String A = "hi你 ...
随机推荐
- 【3】opencv_contrib 4.3.0库配置+opencv安装
相关文章: [1]windows下安装OpenCV(4.3)+VS2017安装+opencv_contrib4.3.0配置 [2]Visual Studio 2017同时配置OpenCV2.4 以及O ...
- C# 通过VMI接口获取硬件ID
使用C#语言实现通过VMI(虚拟机监控器)接口来获取硬件ID的过程.VMI是一种用于虚拟化环境的接口,用于管理虚拟机和宿主机之间的通信和资源共享.具体实现中,需要通过添加System.Manageme ...
- LoopAndLoop【安卓逆向】
LoopAndLoop(阿里CTF) 首先是通用步骤 解压附件后发现是APK文件,打开jeb进行反编译,反编译结果如下: 可以看到程序自定了几个check函数,并且调用了自定义库"lhm&q ...
- 架构设计脱胎换骨!英特尔酷睿Ultra深度解析
英特尔正式发布了第一代酷睿Ultra处理器平台,也就是首个基于Intel 4制程工艺(7nm)打造的移动级处理器平台,其核心代号为Meteor Lake,产品系列贴标设计也采用了全新方案. 同时在命名 ...
- 【Linux】root密码忘记了怎么办【技能篇】一分钟教会你重置root密码
[Linux]root密码重置 文章目录 前言介绍 操作步骤 尾声 前言介绍 那么这里博主先安利一下一些干货满满的专栏啦! 数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是 ...
- DBGRIDEH 底部多列 发现
1.设置底部行数 2.点击footers 单独对每一行进行设置 3.单独对这两行 进行设置 5.看下辅助 所以用的时候可以这样用:WeiTopTradeShow.FieldColumns['top_x ...
- Linux sed输出文件内容的某几行
命令: sed -n "开始行,结束行p" 文件名 sed -n '70,75p' 文件名 # 输出第70行到第75行的内容 sed -n '6p;26 ...
- CF1902
A 只要不是全 \(1\) 即可. B 二分完成天数. C \(x\) 取差的 \(gcd\),\(a_{n+1}\) 见缝插针. D 用一个 map 记录按原始操作序列,要走到 \((x,y)\) ...
- VMware 虚拟机一键去虚拟化工具
前言: 如果你想在 VMware 虚拟机里面多开玩游戏的话,但是现在大多数网游都会检测是否虚拟机,进入游戏被检测到在虚拟机中运行,游戏可能直接闪退.所以就得对 VMware 虚拟机进行去除虚拟化. 原 ...
- 【React】排查两小时,修改一个词,记一个因代码书写不规范导致的生命周期BUG
壹 ❀ 引 因为现在工作主要以修bug为主,日常工作中总是会接触到千奇百怪的前端问题,它可能是代码缺陷导致的程序错误,也可能是方案不合理造成的性能问题,老实说修bug是一件很枯燥的事情,你需要阅读大量 ...