es 3期 第22节-Bucket特殊分桶聚合实战
#### 1.Elasticsearch是数据库,不是普通的Java应用程序,传统数据库需要的硬件资源同样需要,提升性能最有效的就是升级硬件。
#### 2.Elasticsearch是文档型数据库,不是关系型数据库,不具备严格的ACID事务特性,任何企图直接替代严格事务性场景的应用项目都会失败!!!
#### 3.Elasticsearch原则上适合一切非事务性应用场景或能够容许一定的延迟的事务性场景;能最大限度的替代mongodb与传统关系型数据库
##### 索引字段与属性都属于静态设置,若后期变更历史数据需要重建索引才可生效
##### 对历史数据无效!!!!
##### 一定要重建索引!!!!
#### 1、Histogram直方图
## 数据按照直方图的方式分桶聚合直方图直接按照一定的间隔基于数值的直方图分桶;基于日期的直方图分桶;
## 字段类型
## ES专门设计了histogram字段类型
# bucket_key 计算公式
# bucket_key=Math.floor((value-offset)/interval)*interval+ offset
# 查询参数
# histogram,直方图分桶表达式,仅能在数值分桶方面
# field,选定的字段
# interval,值间隔大小,必须为数值
# keyed,是否返回 key 值,默认false
# min_doc_count,限制满足最小文档匹配的分桶
# missing,字段缺失,值默认补充
# extended_bounds,扩展多余分桶数,配合查询条件限制,分桶的范围包括在 min~max之间,用于补足没有数据的间隔分桶。最小值也会限制 min_doc_count起点
# hard_bounds,用于限制分桶的范围,可以缩小分桶数,与extended bounds 内部执行逻辑不一样,善于应用在分桶数非常多的场景,可以大大减小非必要的分桶,减少资源消耗;过滤其它不在范围的分桶
# order,排序,默认按照键值排序,_key,_count 可选。
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_FlightTimeMin":{
"histogram": {
"field": "FlightTimeMin",
// 设置间隔为50,相当于 [0,50),[50,100)。。。
"interval": 50,
"keyed": false,
// 过滤小于这个值的
"min_doc_count": 10,
// 排序
"order": {
"_count": "asc"
},
// 字段缺省后使用这个值作为默认值
"missing": 0
}
}
}
}
# 可以写个query看看第一段的total数据是否正确
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"query":{
"bool": {
"filter": [
{
"range": {
"FlightTimeMin": {
"gte": 0,
"lt": 50
}
}
}
]
}
}
}
# 使用hard_bounds补足缺失的间距
# 数据缺失使用这个来补足特别友好
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_FlightTimeMin":{
"histogram": {
"field": "FlightTimeMin",
// 设置间隔为1000
"interval": 1000,
// 设置补足范围是1000到5000
"extended_bounds": {
"min": 1000,
"max": 5000
}
}
}
}
}
# 使用hard_bounds可以缩小分桶数,相当于取指定的范围,减少资源消耗,用于性能优化
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_FlightTimeMin":{
"histogram": {
"field": "FlightTimeMin",
// 设置间隔为100
"interval": 100,
// 截取范围是800到1000
"hard_bounds": {
"min": 800,
"max": 1000
}
}
}
}
}
### date_histogram 时间范围直方图
# 日期也是数值,在 ES 内部是 Long 存储
# 与普通直方图分桶区别在于,格式化后的键值
## bucket_key 计算公式
# bucket_key= Math.floor(value/interval)*interval
## 查询参数
# 日期直方图查询表达式date histogram,
# field,指定数值字段,必须是日期类型支持的
# calendar_interval,间隔时间,可以设置为 day,或者 1M 数值类型
# fixed_interval,固定时间间隔,支持天以下单位
# format,格式化,日期格式化
# keyed,键值显示
# order,排序
# time_zone,日期区域设置,适合有区域限制的日期类型
# offset,间隔其实位置
# missing,字段缺失默认值
## es存储时间类型的时候最好使用标准utc格式,eg:2024-05-20T00:00:00+0:00
# 使用 calendar_interval 根据时间统计,以周为间隔
# calendar_interval 参数,minute、hour、day、week、 month、year
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_timestamp":{
"date_histogram": {
"field": "timestamp",
// 以周为间隔,
"calendar_interval": "week",
// 设置格式化时间
"format": "yyyy-MM-dd",
// 设置时区
"time_zone": "+00:00"
}
}
}
}
# 使用 fixed_interval 固定时间间隔,以2天为间隔
# fixed_interval 参数,ms、s、m、h、d
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_timestamp":{
"date_histogram": {
"field": "timestamp",
// 以2天为间隔,
"fixed_interval": "2d"
}
}
}
}
## auto_date_histogram 自动设定分桶数量
# auto_date_histogram 相比 date_histogram 更加简化,内部原理差异不多
# 参数
# auto_date_histogram,自动间隔日期直方图查询表达式
# field,指定字段
# buckets,设定分桶数量,之后间隔时间,由ES自动推测
# format,日期格式
# time_zone,时区
# minimum interval,最小间隔时间,可以到秒
# missing,缺失字段默认值
# 具体间隔看返回值的interval字段
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"histogram_timestamp":{
"auto_date_histogram": {
"field": "timestamp",
// 自动分为10个桶
"buckets": 10
}
}
}
}
#### 2、Range范围
# 通过范围限定聚合桶
# 参数
# range,范围分桶查询表达式
# field,指定数值字段
# ranges,多个范围段
# key,指定键值,默认可以不指定,依据from-to
# from,范围起始
# to,范围结束
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"range_FlightTimeMin":{
"range": {
"field": "FlightTimeMin",
"ranges": [
{
// 自定义名称
"key": "custom_name_1",
// 起始和结束值
"from": 0,
"to": 50
},
{
"key": "custom_name_2",
"from": 50,
"to": 100
},{
"key": "custom_name_3",
"from": 100
}
]
}
}
}
}
## 使用脚本
# 使用脚本比较消耗资源,不建议使用
# 使用场景,比如:用户表有用户生日数据,根据用户生日使用脚本算出用户的年龄,然后统计系统的用户年龄分布
# 这里做个简单应用
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":1,
"aggs":{
"range_FlightTimeMin":{
"range": {
"field": "FlightTimeMin",
"script": {
"source": """
doc['FlightTimeMin'].value * 10;
"""
},
"ranges": [
{
// 自定义名称
"key": "custom_name_1",
// 起始和结束值
"from": 0,
"to": 50
},
{
"key": "custom_name_2",
"from": 50,
"to": 100
},{
"key": "custom_name_3",
"from": 100
}
]
}
}
}
}
## 使用runtime_mappings
# 性能比上面的脚本好些
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"runtime_mappings":{
"my_custom_field":{
"type":"double",
"script": {
"source": """
emit(doc['FlightTimeMin'].value * params.custom_param)
""",
"params": {
"custom_param": 10
}
}
}
},
"size":0,
"aggs":{
"range_my_custom_field":{
"range": {
"field": "my_custom_field",
"ranges": [
{
// 自定义名称
"key": "custom_name_1",
// 起始和结束值
"from": 0,
"to": 50
},
{
"key": "custom_name_2",
"from": 50,
"to": 100
},{
"key": "custom_name_3",
"from": 100
}
]
}
}
}
}
## date_range
# 查询参数
# date_range,日期类型范围分桶查询表达式,
# field,指定日期字段
# format,格式化日期
# missing,默认值,缺失字段默认值
# time_zone,时区
# 范围分段分桶ranges,
# from,开始日期,支持固定日期,也支持动态计算方式
# to,结束日期
# key,键值字符串
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"aggs":{
"date_range_timestamp":{
"date_range": {
"field": "timestamp",
"ranges": [
{
// 自定义名称
"key": "custom_name_1",
// 起始和结束值
"from": "2024-05-20",
"to": "2024-06-20"
},{
// 自定义名称
"key": "custom_name_2",
// 起始和结束值
"from": "2024-06-20",
"to": "2024-07-20"
},
{
"key": "custom_name_3",
"from": "now-80d/d",
// 当前时间减去90天
"to": "now-90d/d"
},{
"key": "custom_name_4",
"from": "now/d"
}
]
}
}
}
}
#### 3、Filter过滤
# Filter 单条件分桶过滤
# 查询参数
# 组合多种分桶统计时,可以基于 filter 限制某个分桶下的内容,必须符合筛选条件。
# filter,限制过滤条件,筛选符合条件的数据进行聚合
# 第一种,基于查询条件query过滤,只能拿到过滤后的总数
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"query":{
"bool": {
"filter": [
{
"term": {
"OriginCountry": "US"
}
}
]
}
},
"aggs":{
"status_FlightTimeMin":{
"stats": {
"field": "FlightTimeMin"
}
}
}
}
# 第二种,基于filter分桶过滤,能拿到所有的总数
# 使用场景,只想统计某个条件的值,但是也想知道其他条件都有哪些
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
"size": 100
},
"aggs": {
"filter_OriginCountry": {
// 满足条件的值才做stats统计
"filter": {
"term": {
"OriginCountry": "US"
}
},
"aggs": {
"stats_FlightTimeMin": {
"stats": {
"field": "FlightTimeMin"
}
}
}
}
}
}
}
}
## Filters 多条件分桶过滤
# 有的情况下需要自定义控制分桶的数量与名称,仅仅需要划分出我们限定内容的分桶数据,其余的划分为一组。
# 参数
# filters,多个限制条件分桶过滤查询表达式
# other_bucket,是否显示其它分桶,不在限制条件之内的
#other_bucket_key,设置显示其它分桶名称,默认”other
# filters-filters,多个限制条件,内部语法参考 query 查询课程章节。
# 第一种,采用 query 语法
GET kibana_sample_data_flights/_search
{
"track_total_hits":true,
"size":0,
"query":{
"bool": {
"should": [
{
"term": {
"OriginCountry": "US"
}
},
{
"term": {
"OriginCountry": "IT"
}
}
]
}
},
"aggs":{
"status_FlightTimeMin":{
"stats": {
"field": "FlightTimeMin"
}
}
}
}
# 第二种,采用 filters 分桶机制
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
"size": 100
},
"aggs": {
"filter_OriginCountry": {
// 满足条件的值才做stats统计
"filters": {
"filters": {
"US_term":{
"term": {
"OriginCountry": "US"
}
},
"IT_term":{
"term": {
"OriginCountry": "IT"
}
}
}
},
"aggs":{
"status_FlightTimeMin":{
"stats": {
"field": "FlightTimeMin"
}
}
}
}
}
}
}
}
# 第三种,采用 filter 匿名机制
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
"size": 100
},
"aggs": {
"filter_OriginCountry": {
// 满足条件的值才做stats统计
"filters": {
"filters": [
{
"term": {
"OriginCountry": "US"
}
},
{
"term": {
"OriginCountry": "IT"
}
}
]
},
"aggs":{
"status_FlightTimeMin":{
"stats": {
"field": "FlightTimeMin"
}
}
}
}
}
}
}
}
#### 4、Join关联(不建议使用)
#### 5、Geo地理
# geo_distance
# 字段类型必须是 geo_point才可以
# 参数
# geo_distance,查询参数
# field,地理坐标字段
# origin,中心点坐标,必须符合字段规范
# ranges,分桶范围
# unit,距离单位,默认m
# distance_type,距离计算模型,是平面类型还是球体模型
# unit 参数
# 参数 说明
# m 单位:米
# mi 单位:英里(英美计数法)
# in 单位:英寸(英美计数法)
# yd 单位:码(英美计数法)
# km 单位:公里
# cm 单位:厘米
# mm 单位:毫米
# distance_type 参数
# 参数 说明
# arch 球体模型(默认)
# plane 平面模型
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"geo_distance_DestLocation": {
"geo_distance": {
"field": "DestLocation",
"origin": "-33.94609833,151.177002",
"unit": "m",
"distance_type": "arc",
"keyed":true,
"ranges": [
{
"to": 100000
},
{
"from": 100000,
"to":200000
},
{
"from": 200000,
"to":300000
},
{
"from": 300000
}
]
}
}
}
}
#### 6、composite组合(必须掌握)
# 组合聚合概念相比纯term词项分桶,组合提供了分页的能力,基于快照方式;也提供便利的语法,无需按照嵌套方式组合多个字段分桶聚合;
# 可以组合多种分桶类型,每种分桶类型依然有自己的属性设置;
# 原先的写法
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
"size": 10
},
"aggs": {
"terms_DestCountry": {
"terms": {
"field": "DestCountry",
"size": 10
}
}
}
}
}
}
# composite 写法
# 查询参数
# composite,组合分桶表达式,
# sources,多种分桶组合表达式
# order,排序字段,默认按照键值排序
# size,单页数据大小,默认 10,
# after,设置下一页,组合条件值的起点,即上一页组合分桶结果排序之后最后一条。
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"composite_OriginCountry": {
"composite": {
// 每页5条
"size": 5,
"sources": [
{
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
// 排序
"order": "asc"
}
}
},
{
"terms_DestCountry": {
"terms": {
"field": "DestCountry",
"order": "desc"
}
}
}
],
// 使用返回值中的after_key值翻页
"after": {
"terms_OriginCountry": "AE",
"terms_DestCountry": "RU"
}
}
}
}
}
after_key中的值用于翻页入参
# 也可以使用脚本的方式
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"aggs": {
"composite_OriginCountry": {
"composite": {
// 每页5条
"size": 5,
"sources": [
{
"terms_OriginCountry": {
"terms": {
"field": "OriginCountry",
// 排序
"order": "asc"
}
}
},
{
"terms_DestCountry": {
"terms": {
// 使用脚本
"script":{
"source": """
doc['DestCountry'].value;
""",
"lang": "painless"
}
}
}
}
],
// 使用返回值中的after_key值翻页
"after": {
"terms_OriginCountry": "AE",
"terms_DestCountry": "RU"
}
}
}
}
}
#### 7、Global全局分桶聚合
# 基于全局数据结合聚合,依赖于自己的限定范围条件;
# 有很多应用场景下,期望不受限制条件,依然可以基于全部数据聚合分桶。
GET kibana_sample_data_flights/_search
{
"track_total_hits": true,
"size": 0,
"query":{
"bool": {
"filter": [
{
"term": {
"OriginCountry": "US"
}
}
]
}
},
"aggs": {
// 这里的统计会忽略上面的query条件
"global_OriginCountry": {
"global":{},
"aggs": {
"stats_FlightTimeMin": {
"stats": {
"field": "FlightTimeMin"
}
}
}
},
// 这里的统计会根据上面的query条件过滤
"stats_FlightTimeMin":{
"stats": {
"field": "FlightTimeMin"
}
}
}
}
#### Significant
## Significant Text
# 依据文本分词的词项热度,分桶聚合统计,有点类似suggest特性
# 查询参数
# query,条件
# significant_text,热度分词查询表达式,
# field,指定字段,字段类型必须为 text
GET /_cat/indices?v=true&pretty
# 查看索引字段的格式
GET kibana_sample_data_flights_3share/_mappings
# 使用之前创建的索引, 统计航班目的地机场热度分词
GET kibana_sample_data_flights_3share/_search
{
"track_total_hits": true,
"size": 0,
"query":{
"match": {
"Origin": "airport international"
}
},
"aggs":{
"significant_text_origin":{
"significant_text": {
"field": "Dest"
}
}
}
}
## Significant Terms
# 依据 term 词项热度,分桶聚合统计,有点类似 suggest 特性
# 查询参数
# query,数据限定条件
# significant_terms,热度词项查询表达式
# field,指定字段,字段类型必须为 keyword
# 统计航班目的地国家热度词项
GET kibana_sample_data_flights_3share/_search
{
"track_total_hits": true,
"size": 0,
"query":{
"match": {
"Origin": "airport international"
}
},
"aggs":{
"significant_terms_DestCountry":{
"significant_terms": {
"field": "DestCountry.keyword"
}
}
}
}
#### Sampler
## sampler
# 采样器分桶,是筛选 TopX的数据条目,作为下属分桶的原始数据集合。
# 参数
# sampler,采样器分桶查询表达式
# shard_size,设定提前的分片数据条目数
# 基于 querv查询限定条件,从各个分片提取 100条数据,共300条,作为目的地国家分桶的数据集,并剔除几个目的地国家。调整 shard size与 size 参数数值,对比前后的结果
GET kibana_sample_data_flights_3share/_search
{
"track_total_hits": true,
"size": 0,
"query":{
"match": {
"Origin": "airport international"
}
},
"aggs":{
"sampler_DestCountry":{
"sampler": {
"shard_size": 100
},
"aggs": {
"DestCountry": {
"terms": {
"field": "DestCountry.keyword",
"size": 30,
"exclude": [
"US", "IT"
]
}
}
}
}
}
}
## diversified_sampler
# 多样化采样器,与sampler 采样器类似,不过绑定了一个字段内容,与字段内容值有关联,基于分值计算相近的
# 参数
# diversified_sampler,多样性采样器分桶表达式
# shard_size,设定分片数据提取 TopX条目数
# field,采样器相关绑定字段
# 基于 query 限定条件,依据出发目的地国家的相关性,从各个分片提取 100条数据,进行词项统计。
GET kibana_sample_data_flights_3share/_search
{
"track_total_hits": true,
"size": 0,
"query":{
"match": {
"Origin": "airport international"
}
},
"aggs":{
"diversified_sampler_DestCountry":{
"diversified_sampler": {
"field": "OriginCountry.keyword",
"shard_size": 100
},
"aggs": {
"DestCountry": {
"terms": {
"field": "DestCountry.keyword",
"size": 50
}
}
}
}
}
}
#### 8、特殊分桶聚合建议与经验分享
# 善于运用composite分桶分页机制
# 任何分桶都需要了解背后执行原理(避免不当使用)
# bucket 分桶
# https://www.elastic,co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket.htm
# histogram 直方图分桶
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-histogram-aggregation.html
# histogram 字段类型
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/histogram.htm
# date_histogram 日期直方图
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-datehistogram-aggregation.html
# auto_date_histogram 自动日期直方图
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-autodatehistogram-aggregation.html
# date_range 日期范围
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-daterange-aggregation.htm!
# composite 组合分桶
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-composite-aggregation.html
# geo_distance 地理距离
# https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-aggregations-bucket-geodistance-aggregation.html