作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
聚合
聚合框架用于根据搜索查询提供聚合数据。聚合可以看作在一组文档上构建分析信息的工作单元。执行上下文定义此文档集是什么, 例如,顶级聚合在搜索请求的已执行查询或筛选器的上下文中执行。
聚合有许多不同的类型,每种类型都有自己的目的和输出。为了 更好地理解这些类型,通常将它们分为四大类:
- 存储桶聚合 :构建存储桶(bucket)的聚合系列,其中每个存储桶都与键和文档相关联。当执行聚合时,将对上下文中的每个文档评估所有bucket 条件。当条件匹配时,文档将被视为“属于”相关bucket。在聚合过程结束时,我们将得到一个存储桶列表——每个存储桶都有一组属于它的文档。
- 度量值聚合 :在一组文档上跟踪和计算度量值(metrics)(一个数字)的聚 合。
- 矩阵聚合 :对多个字段进行操作并根据从请求的文档字段中提取的值生成矩阵结果的聚合系列。此聚合系列尚不支持脚本功能。
- 管道聚合 :聚合其他聚合的输出及其相关度量值的聚合。
存储桶聚合可以具有子聚合(度量值聚合或存储桶聚合),在其父聚合生成的存储桶下计算子聚合。嵌套聚合的级别深度没有硬限制 (可以将聚合嵌套在“父”聚合下,它本身就是另一个更高级别聚合 的子聚合)。
1、Metric——度量值聚合
度量值聚合系列中的聚合基于以某种方式从要聚合的文档中提取 的值计算聚合值。这些值通常从文档的字段中提取(使用字段数 据),但也可以使用脚本生成。
数值聚合是一种特殊类型的metrics聚合,它输出是数值。一些聚合输出单个数字度量值(例如avg),称为单值数值度量聚合 (single-value numeric metrics aggregation),其他聚合生成多 个度量值(例如stats),称为多值数值度量聚合(multi-value numeric metrics aggregation)。当这些聚合用作某些存储桶聚合的直接子聚合时,单值和多值数字聚合的区别是需要注意的,某些存储桶聚合能够根据每个存储桶中的数值聚合只对返回的存储桶进行排序。
1.1、avg——均值聚合
均值聚合(avg)是一种单值数值度量聚合,计算从聚合文档中 提取的数值的平均值。这些值可以从文档中的特定数字字段中提取, 也可以由提供的脚本生成。
计算银行账户结欠平均值:聚合的名称(上面的avg_balance)也用作键,也可以自定义的一 个标志符,通过该键可以从返回的响应中检索聚合结果,聚合类型为avg,field定义将计算平均值的文档的数字字段。
GET /bank/_search
{
"aggs": {
"avg_balance": {
"avg": {
"field": "balance"
}
}
},
"size": 0
}
返回:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"avg_balance" : {
"value" : 25714.837
}
}
}
1.1.1、使用脚本计算
也可以通过脚本计算平均值:
GET /bank/_search
{
"aggs": {
"avg_balance": {
"avg": {
"script": {
"source": "doc.balance.value"
}
}
}
},
"size": 0
}
1.1.2、动态参数修正
如果平均值超出了正常范围,需要进行修正。可以使用 动态参数脚本获取新的平均值:
GET /bank/_search
{
"aggs": {
"avg_balance": {
"avg": {
"field": "balance",
"script": {
"lang": "painless",
"source": "_value * params.correction",
"params": {
"correction": 1.2
}
}
}
}
},
"size": 0
}
返回:
{
"took" : 16,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"avg_balance" : {
"value" : 30857.804399999997
}
}
}
1.1.3、missing参数——指定缺省值
missing参数定义如何处理缺少值的文档。默认情况下,它们将 被忽略,但也可以将它们视为具有值:
GET /bank/_search
{
"aggs": {
"avg_balance": {
"avg": {
"field": "balance",
"missing": 10
}
}
},
"size": 0
}
所有的度量聚合都支持脚本功能,对缺少值的处理机制也是相同的。
1.2、min——最小值聚合
GET /bank/_search
{
"aggs": {
"min_balance": {
"min": {
"field": "balance"
}
}
},
"size": 0
}
1.3、max——最大值聚合
GET /bank/_search
{
"aggs": {
"max_balance": {
"max": {
"field": "balance"
}
}
},
"size": 0
}
1.4、sum——求和聚合
GET /bank/_search
{
"aggs": {
"sum_balance": {
"sum": {
"field": "balance"
}
}
},
"size": 0
}
1.5、cardinality——基数统计聚合
计数聚合是一种计算不同值的近似计数的单值数值度量聚合。值 可以从文档中的特定字段中提取,也可以由脚本生成。
GET /bank/_search
{
"aggs": {
"age_count": {
"cardinality": {
"field": "age"
}
}
},
"size": 0
}
返回:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"age_count" : {
"value" : 21
}
}
}
text 类型是分析型类型,默认是不允许进行聚合操作的,如果相对 text 类型进行聚合操作,需要设置其 fielddata 属性为 true,这种方式虽然可以使 text 类型进行聚合操作,但是无法满足精准聚合,如果需要精准聚合,可以设置字段的子域为 keyword。
1.5.1、precision_threshold参数
precision_threshold选项允许以内存开销交换准确性,并定义 唯一的计数,低于该计数的计数是接近准确值的;超过这个值,计数 可能会变得更不准确。支持的最大值为40000,高于此值的阈值将与 40000的阈值具有相同的效果。默认值为3000。
计算精确计数需要将值加载到哈希集中并返回其大小。当处理数 据量比较大时,由于所需的内存使用量和节点之间的每个分片集的通 信需求将占用集群的太多资源,所以哈希集合不会扩太大。
此cardinality聚合基于HyperlogLog++算法,该算法基于散列进 行计数,该散列具有一些有趣属性值:
- 可配置的精度,决定了如何用内存换取精度。
- 在少量数集上具有出色的精度。
- 固定内存使用:无论是否有数百或数十亿个唯一值,内存使 用都仅取决于配置的精度。
GET /bank/_search
{
"aggs": {
"age_count": {
"cardinality": {
"field": "age",
"precision_threshold": 100
}
}
},
"size": 0
}
1.6、stats——基本统计聚合
基本统计,一次性返回 count、max、min、avg、sum:
GET /bank/_search
{
"aggs": {
"stats_query": {
"stats": {
"field": "balance"
}
}
},
"size": 0
}
返回:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"stats_query" : {
"count" : 1000,
"min" : 1011.0,
"max" : 49989.0,
"avg" : 25714.837,
"sum" : 2.5714837E7
}
}
}
1.7、extended_stats——扩展统计聚合
是旧版stats(统计聚 合)的扩展版本,其中添加了额外的计量值,如平方和、方差、标准 偏差和标准偏差界限。
GET /bank/_search
{
"aggs": {
"extended_stats_query": {
"extended_stats": {
"field": "balance"
}
}
},
"size": 0
}
返回:
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"extended_stats_query" : {
"count" : 1000,
"min" : 1011.0,
"max" : 49989.0,
"avg" : 25714.837,
"sum" : 2.5714837E7,
"sum_of_squares" : 8.58626807735E11,
"variance" : 1.9737396579843104E8,
"variance_population" : 1.9737396579843104E8,
"variance_sampling" : 1.975715373357668E8,
"std_deviation" : 14048.984511288745,
"std_deviation_population" : 14048.984511288745,
"std_deviation_sampling" : 14056.014276307733,
"std_deviation_bounds" : {
"upper" : 53812.80602257749,
"lower" : -2383.1320225774907,
"upper_population" : 53812.80602257749,
"lower_population" : -2383.1320225774907,
"upper_sampling" : 53826.86555261546,
"lower_sampling" : -2397.191552615466
}
}
}
}
extended_stats 聚 合 返 回 包 括 一 个 名 为 std_deviation_bounds的对象,该对象提供一个与平均值正负两个 标准差的间隔。这是一种可视化数据差异的有用方法。如果需要不同的边界,例如三个标准偏差,可以在请求中设置sigma:
GET /bank/_search
{
"aggs": {
"extended_stats_query": {
"extended_stats": {
"field": "balance",
"sigma": 3
}
}
},
"size": 0
}
sigma参数用来控制应显示多少标准偏差+/-与平均值。
sigma可以是任何非负浮点数,如1.5,值0有效,但只返回上界 和下界的平均值。
默认情况下会显示标准偏差及其边界,但它们并不总是适用于所 有数据集。数据必须是正态分布的。标准偏差后面的统计数据假定为 正态分布的数据,因此,如果数据严重向左或向右倾斜,返回的值将 是具有误导性的。
1.8、percentiles——百分位统计
百分位数聚合是一种多值数值聚合,它计算从聚合文档中提取的数值的一个或多个百分位数。这些值可以从文档中的特定数字字段中提取,也可以由提供的脚本生成。
百分位数表示观察值的某个百分比出现的点。例如,95%是大于 观察值95%的值。
百分位数通常用于查找异常值。在正态分布中,0.13%和 99.87%表示区间上下限与平均值的三个标准差。任何超出三个标准 差区间的数据通常被视为异常。
当检索到一个百分位数范围时,它们可以用来估计数据分布,并 确定数据是否是歪斜的、双峰的等。
GET /bank/_search
{
"aggs": {
"per_age": {
"percentiles": {
"field": "age"
}
}
},
"size": 0
}
默认情况下,百分位数度量将生成百分位数范围:[1、5、25、 50、75、95、99]。
{
"took" : 36,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"per_age" : {
"values" : {
"1.0" : 20.0,
"5.0" : 21.0,
"25.0" : 25.0,
"50.0" : 31.0,
"75.0" : 35.0,
"95.0" : 39.0,
"99.0" : 40.0
}
}
}
}
从结果中可以看出,年龄分布在20~40之间,主要分布在25-35之间。
如果我们只对极端值、异常值感兴趣,可以指定我们感兴趣的百分比:
GET /bank/_search
{
"aggs": {
"per_age": {
"percentiles": {
"field": "age",
"percents": [
1,
5,
95,
99
]
}
}
},
"size": 0
}
返回:
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"per_age" : {
"values" : {
"1.0" : 20.0,
"5.0" : 21.0,
"95.0" : 39.0,
"99.0" : 40.0
}
}
}
}
默认情况下,keyed标志设置为true,它将唯一的字符串键与每 个bucket相关联,并将范围作为哈希而不是数组返回。将keyed标志 设置为false将禁用此行为:
GET /bank/_search
{
"aggs": {
"per_age": {
"percentiles": {
"field": "age",
"keyed": false,
"percents": [
1,
5,
95,
99
]
}
}
},
"size": 0
}
返回:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"per_age" : {
"values" : [
{
"key" : 1.0,
"value" : 20.0
},
{
"key" : 5.0,
"value" : 21.0
},
{
"key" : 95.0,
"value" : 39.0
},
{
"key" : 99.0,
"value" : 40.0
}
]
}
}
}
1.9、percentile_rank——百分比排名聚合
百分比排名聚合是一种多值数值度量聚合,它计算从聚合文档中 提取的数值的一个或多个百分位数排名。
这里有另外一个紧密相关的度量叫 percentile_ranks 。 percentiles 度量告诉我们落在某个百分比以下的所有文档的最小值。例如,如果 50 百分位是 119ms,那么有 50% 的文档数值都不超过 119ms。 percentile_ranks 告诉我们某个具体值属于哪个百分位。119ms 的 percentile_ranks 是在 50 百分位。 这基本是个双向关系,例如:
- 50 百分位是 119ms。
- 119ms 百分位等级是 50 百分位。
GET /bank/_search
{
"aggs": {
"per_age_ranks": {
"percentile_ranks": {
"field": "age",
"values": [20, 25, 35, 40]
}
}
},
"size": 0
}
返回:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1000,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"per_age_ranks" : {
"values" : {
"20.0" : 4.3,
"25.0" : 26.400000000000002,
"35.0" : 75.6,
"40.0" : 100.0
}
}
}
}
1.10、top_hits——顶部命中聚合
顶部命中(top_hits)聚合跟踪正在聚合的最相关若干文档。此聚合器用作子聚合器,以便每个bucket可以聚合顶部匹配的文档。
top_hits聚合器可以有效地用于通过bucket聚合器按特定字段对结果集进行分组。一个或多个bucket聚合器确定将结果集切片到哪个 属性中。
top_hits聚合器支持的参数如下:
- from:要获取的第一个结果的偏移量(组内偏移量,由于每 个分组的结果数不同,有可能会造成有的组没有结果)。
- size:每个桶返回的结果集的最大数量。默认情况下,返回 前三个匹配的匹配。
- sort:如何对最匹配的匹配进行排序。默认情况下,命中文 档按主查询的分数排序。
通过示例讲解,先准备索引和数据。这里以菜谱为例,name为 菜谱名,cla为菜系,rating为用户的累积平均评分。
PUT /recipes
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"rating": {
"type": "float"
},
"cla": {
"type": "keyword"
}
}
}
}
POST /recipes/_bulk
{"index": {"_id":1}}
{"name":"清蒸鱼头", "rating":1,"cla":"湘菜"}
{"index": {"_id":2}}
{"name":"剁椒鱼头", "rating":2,"cla":"湘菜"}
{"index": {"_id":3}}
{"name":"红烧鲫鱼", "rating":3,"cla":"湘菜"}
{"index": {"_id":4}}
{"name":"鲫鱼汤(辣)", "rating":3,"cla":"湘菜"}
{"index": {"_id":5}}
{"name":"鲫鱼汤(微辣)", "rating":4,"cla":"湘菜"}
{"index": {"_id":6}}
{"name":"鲫鱼汤(变态辣)", "rating":5,"cla":"湘菜"}
{"index": {"_id":7}}
{"name":"广式鲫鱼汤", "rating":5,"cla":"粤菜"}
{"index": {"_id":8}}
{"name":"鱼香肉丝", "rating":2,"cla":"川菜"}
{"index": {"_id":9}}
{"name":"奶油鲍鱼汤", "rating":2,"cla":"西菜"}
每个菜系展示三个菜,并按评分排序
GET /recipes/_search
{
"query": {
"match": {
"name": "鱼"
}
},
"sort": [
{
"rating": {
"order": "desc"
}
}
],
"aggs": {
"cal": {
"terms": {
"field": "cla",
"size": 10
},
"aggs": {
"rated": {
"top_hits": {
"sort": [
{"rating": {"order": "desc"}}
],
"size": 3,
"from": 0
}
}
}
}
},
"size": 0,
"from": 0
}
返回:
{
"took" : 209,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 9,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"cal" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "湘菜",
"doc_count" : 6,
"rated" : {
"hits" : {
"total" : {
"value" : 6,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "recipes",
"_type" : "_doc",
"_id" : "6",
"_score" : null,
"_source" : {
"name" : "鲫鱼汤(变态辣)",
"rating" : 5,
"cla" : "湘菜"
},
"sort" : [
5.0
]
},
{
"_index" : "recipes",