《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.21.Aggregations(1) https://developer.aliyun.com/article/1229245
二、指标聚合(Metrics)
我们以销售产品的场景定义如下 mapping:
put order { 'mappings' : { 'properties' : { 'sales_name' : { 'type' : 'keyword' }, 'product_name' : { 'type' : 'keyword' }, 'brand' : { 'type' : 'keyword' }, 'count' : { 'type' : 'integer' }, 'price' : { 'type' : 'double' }, 'order_time' : { 'type' : 'date' } } } }
模拟数据如下:
POST _bulk {"index":{"_index":"order","_id":1}} {"sales_name":"Andy","product_name":"iphone12","brand":"Apple","count":20,"price":"8999.65","order_time":"2021-09-03"} {"index":{"_index":"order","_id":2}} {"sales_name":"Andy","product_name":"mate10","brand":"HUAWEI","count":22,"price":"9999.20","order_time":"2021-08-03"} {"index":{"_index":"order","_id":3}} {"sales_name":"Lily","product_name":"iphone12","brand":"Apple","count":25,"price":"7999.56","order_time":"2021-08-23"} {"index":{"_index":"order","_id":4}} {"sales_name":"Mango","product_name":"mate11","brand":"HUAWEI","count":30,"price":"8354.09","order_time":"2021-09-25"} {"index":{"_index":"order","_id":5}} {"sales_name":"Lisa","product_name":"iphone13","brand":"Apple","count":26,"price":"9976.34","order_time":"2021-10-11"} {"index":{"_index":"order","_id":6}} {"sales_name":"Lisa","product_name":"mate11","brand":"HUAWEI","count":28,"price":"7849.46","order_time":"2021-07-11"} {"index":{"_index":"order","_id":7}} {"sales_name":"Amy","product_name":"mate11","brand":"HUAWEI","count":28,"order_time":"2021-07-11"}
1、平均值聚合 avg
平均值聚合属于单值度量聚合,从聚合文档中计算某个字段的平均值,参与计算的字段需为数值型。
1)基础用法
以下例子计算了订单数据中产品的平均售价,我们定义该平均值的名字为 avg_price ,该字段也将作为结果返回:
POST /order/_search?size=0 { "aggs" : { "avg_price" : { "avg" : { "field" : "price" } } } } 其中size为返回结果数量,等价于下面的写法 POST /order/_search { "size": 0, "aggs" : { "avg_price" : { "avg": { "field": "price" } } } }
返回结果:
{ ... "aggregations" : { "avg_price" : { "value" : 8863.050000000001 } } }
查询条数,这里设置为0,因为我们不关心搜索到的数据,只关心聚合结果,提高效率。
2)缺失值
默认情况下,当文档中缺失计算字段值时,该文档将会被忽略,若我们希望使用这部分文档,可以通过设置 missing 参数。在上述数据中,_id 等于 7 的数据,价格列缺失,通过以下设置,缺失字段的 price 将按照 0 来计算。
POST /order/_search?size=0 { "aggs" : { "avg_price" : { "avg" : { "field" : "price", "missing" : 0 } } } }
返回结果:
{ ... "aggregations" : { "avg_price" : { "value" : 7596.900000000001 } } }
由结果可以看出设置 missing 值后,_id 为 7 的数据参与了计算,平均值变小了,这就是 missing 的作用,以下其他指标的 missing 与之类似,将不再赘述。
3)Histogram fields
当计算平均值的字段为直方图字段时,聚合结果是使用每组数据中的 value 位置的数据乘以相同位置的 count 从而计算出的加权平均值。
以存储不同网络的预聚合直方图和延迟度量的索引为例,数据结构如下:
PUT metrics_index { "mappings" : { "properties" : { "network_name":{ "type" : "keyword" }, "latency_histo" : { "type" : "histogram" } } } } PUT metrics_index/_doc/1 { "network_name" : "net-1", "latency_histo" : { "values" : [0.1, 0.2, 0.3, 0.4, 0.5], "counts" : [3, 7, 23, 12, 6] } } PUT metrics_index/_doc/2 { "network_name" : "net-2", "latency_histo" : { "values" : [0.1, 0.2, 0.3, 0.4, 0.5], "counts" : [8, 17, 8, 7, 6] } }
计算 latency_histo 字段的聚合结果:
POST /metrics_index/_search?size=0 { "aggs": { "avg_latency": { "avg": { "field": "latency_histo" } } } }
计算 latency_histo 平均值的方法为找到所有的文档,将所有文档中 value 乘以对应位置的
count 后计算出总和,再除以所有文档 count 之和,由此可得到如下结果。
{ ... "aggregations" : { "avg_latency" : { "value" : 0.29690721649484536 } } }
4)脚本
纠正价格后重新计算:
GET order/_search?size=0 { "runtime_mappings": { "price.corrected": { "type": "double", "script": { "source": "emit(Math.max(100, doc['price'].value * params.correction))", "params": { "correction": 0.8 } } } }, "aggs": { "avg_corrected_grade": { "avg": { "field": "price.corrected" } } } }
需要注意的是,如果脚本计算的字段中存在缺失的情况,那么在使用脚本的时候需要加上对字段非 null 的判断,否则将会出现计算失败的错误。例如:
if (price ! = null) emit(price);
《Elastic Stack 实战手册》——三、产品能力——3.4.入门篇——3.4.2.Elasticsearch基础应用——3.4.2.21.Aggregations(3) https://developer.aliyun.com/article/1229243