尝试聚合
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : { (1)
"popular_colors" : { (2)
"terms" : { (3)
"field" : "color"
}
}
}
}
结果:
{
...
"hits": {
"hits": [] (1)
},
"aggregations": {
"popular_colors": { (2)
"buckets": [
{
"key": "red", (3)
"doc_count": 4 (4)
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}
添加度量指标
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": { (1)
"avg_price": { (2)
"avg": {
"field": "price" (3)
}
}
}
}
}
}
结果:
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"avg_price": { (1)
"value": 32500
}
},
{
"key": "blue",
"doc_count": 2,
"avg_price": {
"value": 20000
}
},
{
"key": "green",
"doc_count": 2,
"avg_price": {
"value": 21000
}
}
]
}
}
...
}
嵌套桶
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": { (1)
"avg": {
"field": "price"
}
},
"make": { (2)
"terms": {
"field": "make" (3)
}
}
}
}
}
}
结果:
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"make": { (1)
"buckets": [
{
"key": "honda", (2)
"doc_count": 3
},
{
"key": "bmw",
"doc_count": 1
}
]
},
"avg_price": {
"value": 32500 (3)
}
},
...
}
告诉我们:
1、红色车有4量
2、红色车的平均售价32500
3、其中3辆是honda,1辆是bmw
最后的修改(为每个汽车厂商计算最低和最高的价格)
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"colors": {
"terms": {
"field": "color"
},
"aggs": {
"avg_price": { "avg": { "field": "price" }
},
"make" : {
"terms" : {
"field" : "make"
},
"aggs" : { (1)
"min_price" : { "min": { "field": "price"} }, (2)
"max_price" : { "max": { "field": "price"} } (3)
}
}
}
}
}
}
结果:
{
...
"aggregations": {
"colors": {
"buckets": [
{
"key": "red",
"doc_count": 4,
"make": {
"buckets": [
{
"key": "honda",
"doc_count": 3,
"min_price": {
"value": 10000 (1)
},
"max_price": {
"value": 20000 (1)
}
},
{
"key": "bmw",
"doc_count": 1,
"min_price": {
"value": 80000
},
"max_price": {
"value": 80000
}
}
]
},
"avg_price": {
"value": 32500
}
},
...
告诉我们:
1、4辆红色车
2、红色车的平均售价是32500
3、3辆红色车是honda,1辆是bmw
4、最便宜的红色honda是10000
5、最贵的红色honda是20000
条形图
聚合能够被转换成图表和图形
{
"size" : 0,
"aggs":{
"price":{
"histogram":{ (1)
"field": "price",
"interval": 20000
},
"aggs":{
"revenue": {
"sum": { (2)
"field" : "price"
}
}
}
}
}
}
1、直方图(条形图)histogram要求两个参数,一个数值字段以及一个定义桶大小间隔。
2、sum度量嵌套在每个售价区间内,用来显示每个区间内的总收入。
响应如下:
{
...
"aggregations": {
"price": {
"buckets": [
{
"key": 0,
"doc_count": 3,
"revenue": {
"value": 37000
}
},
{
"key": 20000,
"doc_count": 4,
"revenue": {
"value": 95000
}
},
{
"key": 80000,
"doc_count": 1,
"revenue": {
"value": 80000
}
}
]
}
}
}
key:0代表0-19999,以此类推
当然,我们可以为任何聚合输出的分类和统计结果创建条形图,而不只是直方图。
最受欢迎10种汽车以及它们的平均售价、标准差这些信息
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"makes": {
"terms": {
"field": "make",
"size": 10
},
"aggs": {
"stats": {
"extended_stats": {
"field": "price"
}
}
}
}
}
}
上述代码会按受欢迎度返回制造商列表以及它们各自的统计信息。
未给出响应,需要实验。
按时间统计
无论什么数据,只要带有时间戳,就可以进行data_histogram分析,在时间维度上构建指标分析。
date_histogram倾向于转换成线状图用以展示时间序列
histogram bucket是可以处理日期的,但是它不能自动识别日期。
date_histogram可以指定时间段、还能知道时间之间的关系,还能合理处理时区
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "month", (1)
"format": "yyyy-MM-dd" (2)
}
}
}
}
1、时间间隔
2、日期格式
响应结果如下所示,表示每月销售多少台汽车
{
...
"aggregations": {
"sales": {
"buckets": [
{
"key_as_string": "2014-01-01",
"key": 1388534400000,
"doc_count": 1
},
{
"key_as_string": "2014-02-01",
"key": 1391212800000,
"doc_count": 1
},
{
"key_as_string": "2014-05-01",
"key": 1398902400000,
"doc_count": 1
},
{
"key_as_string": "2014-07-01",
"key": 1404172800000,
"doc_count": 1
},
{
"key_as_string": "2014-08-01",
"key": 1406851200000,
"doc_count": 1
},
{
"key_as_string": "2014-10-01",
"key": 1412121600000,
"doc_count": 1
},
{
"key_as_string": "2014-11-01",
"key": 1414800000000,
"doc_count": 2
}
]
...
}
没有数据默认不返回。可以设置参数min_doc_count,强制返回buckets,即使buckets可能为空;extended_bounds,最大、最小日期范围
GET /cars/transactions/_search
{
"size" : 0,
"aggs": {
"sales": {
"date_histogram": {
"field": "sold",
"interval": "quarter", (1)
"format": "yyyy-MM-dd",
"min_doc_count" : 0,
"extended_bounds" : {
"min" : "2014-01-01",
"max" : "2014-12-31"
}
},
"aggs": {
"per_make_sum": {
"terms": {
"field": "make"
},
"aggs": {
"sum_price": {
"sum": { "field": "price" } (2)
}
}
},
"total_sum": {
"sum": { "field": "price" } (3)
}
}
}
}
}
1、每个季度
2、计算每种品牌的总销售金额
3、计算所有全部品牌的汇总销售金额
响应结果:
{
....
"aggregations": {
"sales": {
"buckets": [
{
"key_as_string": "2014-01-01",
"key": 1388534400000,
"doc_count": 2,
"total_sum": {
"value": 105000
},
"per_make_sum": {
"buckets": [
{
"key": "bmw",
"doc_count": 1,
"sum_price": {
"value": 80000
}
},
{
"key": "ford",
"doc_count": 1,
"sum_price": {
"value": 25000
}
}
]
}
},
...
}
聚合表能做很多事情,例如kibana-用聚合构建的实时分析面板
范围限定的聚合
默认情况下,聚合是基于我们查询匹配的文档集合进行计算的。可以利用查询对聚合限定范围。
全局桶
通常我们希望聚合是在查询范围内的,但有时我们也想要搜索它的子集,而聚合的对象确实所有数据。
例如:
GET /cars/transactions/_search
{
"size" : 0,
"query" : {
"match" : {
"make" : "ford"
}
},
"aggs" : {
"single_avg_price": {
"avg" : { "field" : "price" } (1)
},
"all": {
"global" : {}, (2)
"aggs" : {
"avg_price": {
"avg" : { "field" : "price" } (3)
}
}
}
}
}
1、聚合操作在查询范围内
2、global全局桶没有参数
3、聚合操作针对所有文档,忽略汽车品牌
过滤和聚合
聚合范围限定还有一个自然的扩展就是过滤。因为聚合是在查询结果范围内操作的,任何可以适用于查询的过滤器也可以应用在聚合上。
例如:
GET /cars/transactions/_search
{
"size" : 0,
"query" : {
"constant_score": {
"filter": {
"range": {
"price": {
"gte": 10000
}
}
}
}
},
"aggs" : {
"single_avg_price": {
"avg" : { "field" : "price" }
}
}
}
过滤桶
如果我们只想对聚合结果过滤怎么办?
我们希望显示用户搜索的结果,也希望显示(与搜索匹配的)上个月度汽车的平均售价。
GET /cars/transactions/_search
{
"size" : 0,
"query":{
"match": {
"make": "ford"
}
},
"aggs":{
"recent_sales": {
"filter": { (1)
"range": {
"sold": {
"from": "now-1M"
}
}
},
"aggs": {
"average_price":{
"avg": {
"field": "price" (2)
}
}
}
}
}
}
1、使用过滤桶在查询范围基础上应用过滤器(当文档满足过滤桶条件时,加入到桶内)
2、avg度量智慧对ford并且是上个月售出的文档计算平均售价
后过滤器
只过滤搜索结果,不过滤聚合结果。可以使用post_filter。
它是接收一个过滤器的顶层搜索请求元素。这个过滤器在查询之后执行。
例如:
GET /cars/transactions/_search
{
"size" : 0,
"query": {
"match": {
"make": "ford"
}
},
"post_filter": { (1)
"term" : {
"color" : "green"
}
},
"aggs" : {
"all_colors": {
"terms" : { "field" : "color" }
}
}
}
查询部分找到所有的ford汽车,然后用terms聚合创建一个颜色列表。
post_filter会过滤搜索结果,只展示绿色ford汽车。所以聚合不受影响。
多桶排序
多值桶(terms、histogram、date_histogram)动态生成很多桶。默认根据doc_count降序排列。有时我们需要修改这个顺序,不同的桶有着不同的处理方式。
1、内置排序
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"terms" : {
"field" : "color",
"order": {
"_count" : "asc" (1)
}
}
}
}
}
order对象,允许我们根据以下几个值中的一个值进行排序:
_count,按doc_count值排列,对terms、histogram、date_histogram有效
_term,按词项的字符串值的字母顺序排序。只在terms内使用
_key,按每个桶的键值数值排序,与_term类似,只在histogram和date_histogram内使用
2、按度量排序
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"terms" : {
"field" : "color",
"order": {
"avg_price" : "asc" (2)
}
},
"aggs": {
"avg_price": {
"avg": {"field": "price"} (1)
}
}
}
}
}
计算每个桶的平均售价、桶按照计算平均值的升序排序
多个度量值:使用.
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"terms" : {
"field" : "color",
"order": {
"stats.variance" : "asc" (1)
}
},
"aggs": {
"stats": {
"extended_stats": {"field": "price"}
}
}
}
}
}
3、基于“深度”度量排序
定义更深的路径,可以使用>
,路径上的每个桶都必须是单值的。
目前只有三个单值桶filter、global、reverse_nested
创建一个汽车售价的直方图,但是按照红色和绿色(不包括蓝色)车各自的方差来排序:
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"colors" : {
"histogram" : {
"field" : "price",
"interval": 20000,
"order": {
"red_green_cars>stats.variance" : "asc" (1)
}
},
"aggs": {
"red_green_cars": {
"filter": { "terms": {"color": ["red", "green"]}}, (2)
"aggs": {
"stats": {"extended_stats": {"field" : "price"}} (3)
}
}
}
}
}
}
1.按照嵌套度量的方差对桶的直方图进行排序
2.因为我们你用单值过滤器,我们可以使用嵌套排序
3.按照生成的度量对统计结果进行排序。
近似聚合
有些算法可以分布执行,高度并行的,它们无须任何额外代价,就能在多台机器上并行执行。例如计算max
1、把请求广播到所有分片。
2、查看每个文档的price字段。如果price>current_max,则替换 。
3、返回所有分片的最大price并传给协调节点。
4、找到从所有分片返回的最大price。这是最终的最大值
这个算法随着机器的增长而横向扩展,无须任何协调操作(机器之间不需要讨论中间结果)
然而不是所有算法都如max这样简单。需要再算法的性能和内存使用上做出权衡。
三角因子模型:大数据、精确性和实时性。
我们需要选择其中两项:
精确+实时:数据存入单台机器的内存之中。
大数据+精确:例如hadoop。可以处理PB级的数据并且为我们提供精确的答案,但可能需要几周才能出结果。
大数据+实时:近似算法为我们提供准确但不精确的结果
ES支持两种近似算法cardinality和percentiles。
统计去重后的数量
cardinality:提供一个字段的基数,即该字段的distinct或者unique值的数目
经销商销售汽车颜色的数量:
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"distinct_colors" : {
"cardinality" : {
"field" : "color"
}
}
}
}
返回:
...
"aggregations": {
"distinct_colors": {
"value": 3
}
}
...
每个月有多少颜色的车被售出
GET /cars/transactions/_search
{
"size" : 0,
"aggs" : {
"months" : {
"date_histogram": {
"field": "sold",
"interval": "month"
},
"aggs": {
"distinct_colors" : {
"cardinality" : {
"field" : "color"
}
}
}
}
}
}
cardinality度量是一个近似算法,基于HyperLogLog算法。
可配置的精度,更精确=更多内存
小的数据集精度非常高
可以固定内存使用量
可以通过参数precision_threshold(0-40000)配置精度
值在100以内时会得到非常准确的结果
HyperLogLog只是简单的对数据做哈希以及一些位操作。想进一步优化的话可以在索引时将字段内容的哈希值计算好
百分位计算
percentiles百分位数度量
使用一个TDigest算法,特性如下:
1、百分位的准确度与百分位的极端程度相关。1%或99%要比50%要准确
2、数据集合较小时,百分位非常准确
3、随着桶里数据的增长,算法会能准确度和内存节省之间做出权衡。
通过聚合发现异常指标
significant_terms分析统计你的数据并通过对比正常数据找到可能有异常频次的指标。
基于流程程度推荐
基于统计的推荐
Doc Values不是由JVM来管理,本质上是一个序列化的列式存储
Doc Values默认对所有字段启用,除了analyzed strings。所以我们可以选择对数据集里面的大多数字段进行聚合和排序操作。但是如果确定永远不会对某些字段进行聚合、排序或是脚本操作,可以禁用Doc Values,从而节省磁盘空间。
聚合与分析
fielddata数据结构,常驻于JVM内存堆中。(逐步淘汰)
not_analyzed字段,可以通过doc values节省内存
analyzed字段,使用fielddata并加载到内存中。是否有ngrams有一个非常大的基础,如果是,对内存来说极度不友好
fielddata熔断器、过滤、
预加载:预加载 fielddata、预加载全局序号、缓存预热
优化聚合查询
深度优先与广度优先,剪枝