对ES官网的reference的翻译,同时也是备忘,ES版本为7.5
下面是正文翻译,附上原文链接
==================================================================================================
基数聚合
单值指标聚合,计算不同值的近似数量。这些值可以从文档中某些特定的数值字段中提取出来,也可以使用给定的脚本生成。
假设你索引了商店的零售额并想要计算匹配下面查询的已经卖出去的不同商品的个数:
curl -X POST http://host_ip:host_port/sales/_search?pretty
-H 'content-type:application/json'
-d '{
"size": 0,
"aggs": {
"type_count": {
"cardinality": {
"field": "type"
}
}
}
}'
下面是响应:
{
...
"aggregations" : {
"type_count" : {
"value" : 3
}
}
}
精度控制
基数聚合也支持precision_threshold选项:
curl -X POST http://host_ip:host_port/sales/_search?pretty
-H 'content-type:application/json'
-d '{
"size": 0,
"aggs": {
"type_count": {
"cardinality": {
"field": "type",
"precision_threshold": 100
}
}
}
}'
precision_threshold选项允许牺牲内存提高精度,并定义了一个值,在这个值以下,计数应该尽可能准确;在这个值以上,计数有可能会没那么精确。precision_threshold选项支持的最大值是40000,比这个值大的数会默认跟40000一样的效果,默认值为3000.
计数是近似的
计算精确的计数需要将数值导入hash集合并返回集合的大小,当处理高基数集和/或较大的值时无法扩展,因为所需的内存使用情况以及在节点之间传递每个分片集的需求会占用过多的群集资源。
基数聚合基于HyperLogLog++算法,该算法基于数值的哈希来计数,算法有下面一些特性:
1)可配置的精度,决定了如何为了精度而牺牲内存
2)低基数集合的准确性很高
3)固定的内存使用:不管集合中是否存在数十或者数百亿独特的值,内存的使用仅仅依赖于配置的精度
假设精度的阈值为c,那么我们使用的实现方式需要大约c*8bytes的内存。
下面的图表显示了在精度阈值之上和阈值之下的误差变化情况:
对于图中的三种阈值,在配置的阈值之前的基数计数都是准确的。尽管没有保证,这有很大可能就是事实。实际上的精度依赖于数据集。一般来说,大部分的数据集都展示了很好的准确性。我们也需要注意的是,即便阈值低至100,当对百万的数据进行计数时,误差也很低(图中显示了1-6%的误差)。
HyperLogLog++算法依赖于哈希后的值的前序0的个数,数据集哈希后的准确分布会影响基数聚合的准确率。
预先计算的哈希
对于有高基数的字符串字段,在索引中先存储该字段的值的哈希然后在对这个字段进行基数聚合可能会比较快。预先计算哈希既可以通过从客户端侧提供哈希值实现也可以通过让ES使用mapper-murmur3插件计算哈希值。
NOTE:提前计算的哈希值通常来说只对非常大的或者高基数的字段有用,因为它能够节省CPU和内存。但是,对于数值字段,哈希是非常快的并且存储原始值会比存储哈希值花费相等或者更少的内存。对于低基数的字符串字段也是如此,特别是考虑到这些字段已进行了优化,以确保每个段的每个唯一值最多计算一次哈希。
脚本
基数指标支持脚本,但是由于哈希值需要实时计算,因此性能会受到明显影响。
curl -X POST http://host_ip:host_port/sales/_search?pretty
-H 'content-type:application/json'
-d '{
"size": 0,
"aggs": {
"type_promoted_count": {
"cardinality": {
"script": {
"lang": "painless",
"source": "doc['type'].value+' '+doc['promoted'].value"
}
}
}
}
}'
上面的请求会讲script参数当作painless脚本语言编写的没有参数的内联脚本处理。为了使用缓存的脚本,使用下面的语法:
curl -X POST http://host_ip:host_port/sales/_search?pretty
-H 'content-type:application/json'
-d '{
"size": 0,
"aggs": {
"type_promoted_count": {
"cardinality": {
"script": {
"id": "my_script",
"params": {
"type_field": "type",
"promoted_field": "promoted"
}
}
}
}
}
}'
缺失的值
missing这个参数定义了缺失某个字段的文档应该如何被处理,默认的这些文档会被忽略,但我们也能通过假设它们这个字段有值来处理这些文档。
curl -X POST http://host_ip:host_port/sales/_search?pretty
-H 'content-type:application/json'
-d '{
"size": 0,
"aggs": {
"tag_cardinality": {
"cardinality": {
"field": "tag",
"missing": "N/A"
}
}
}
}
}'
上面的请求定义缺失tag域值的文档将会落入跟tag域值为N/A的文档相同的桶中。