面试官问我会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你 ...
随机推荐
- c和c++开发工具之clion和vs
个人体验结果 如果是CMake或者要跨平台的话,建议使用CLion 像我在看书写练习题的话,Clion使用cmake编译c/c++源码更简单上手使用. 如果项目不大,两者都可以.如果关联子项目或第三方 ...
- 21.9 Python 使用Selenium库
Selenium是一个自动化测试框架,主要用于Web应用程序的自动化测试.它可以模拟用户在浏览器中的操作,如打开网页.点击链接.填写表单等,并且可以在代码中实现条件判断.异常处理等功能.Seleniu ...
- Cheat Engine 官方教程汉化
CE修改器官方教程汉化版,区别于前款教程,官方教程中使用的是Tutorial64位程序,如下是经过翻译后的官方文档. 第一步:欢迎 当教程启动时,您应该会看到类似的东西,您只需在阅读帮助文本后单击&q ...
- CF1000F One Occurrence题解
题目链接:CF 或者 洛谷 感觉很经典的题,而且给的 \(5e5\),虽然莫队之类的很好想,但完全没必要去考虑这类算法,这种数据范围常数又大又开盲盒.很显然的具有单 \(log\) 的算法. 回忆下经 ...
- 如何计算DG环境下Redo传输所需的带宽?
MOS有篇文章: How To Calculate The Required Network Bandwidth Transfer Of Redo In Data Guard Environments ...
- IntelliJ IDEA 查看一个接口的实现类。
- ASP.NET Core分布式项目实战(oauth2与open id connect 对比)--学习笔记
任务14:oauth2与open id connect 对比 以微博开放平台为例(微博登录接入--授权机制): https://open.weibo.com/wiki/授权机制 可以看到微博登录接入使 ...
- JS 前序遍历、中序遍历、后序遍历、层序遍历详解,深度优先与广度优先区别,附leetcode例题题解答案
壹 ❀ 引 按照一天一题的速度,不知不觉已经刷了快两多月的leetcode了,因为本人较为笨拙,一道简单的题有时候也会研究很久,看着提交了两百多次,其实也才解决了70来道简单题,对于二分法,双指针等也 ...
- NVME(学习笔记七)—Atomicity Operation
5.21.1.10 Write Atomicity Normal 这个特性控制AWUN和NAWUN参数的操作.设置的属性值在set Feature命令的Dword 11中表明. 如果提交Get Fea ...
- STM32F401CCU6与MFRC522接线及读取示例
硬件准备 stm32f401ccu6最小开发板 rfid-rc522开发板 usb2ttl转接, 可以用pl2303, ch340, CP2102, FT232 Mifare 1K卡, UID长度4字 ...