基数聚合
计算不同值的近似计数的单个值度量聚合。值可以从文档中的特定字段中提取,也可以由脚本生成。
假设您正在为商店销售编制索引,并希望计算与查询匹配的已售出产品的唯一数量:
POST /sales/_search?size=0
{
"aggs" : {
"type_count" : {
"cardinality" : {
"field" : "type"
}
}
}
}
响应:
{
...
"aggregations" : {
"type_count" : {
"value" : 3
}
}
}
精准度控制
此聚合还支持精度阈值选项:
POST /sales/_search?size=0
{
"aggs" : {
"type_count" : {
"cardinality" : {
"field" : "type",
"precision_threshold": 100 <1>
}
}
}
}
-
Precision_Threshold(精度阈值)选项允许以内存交换准确性,并定义一个唯一的计数,低于该计数的计数应接近准确性。超过这个值,计数可能会变得更加模糊。支持的最大值为40000,高于此值的阈值将与40000的阈值具有相同的效果。默认值为3000。
计数是近似值
计算精确计数需要将值加载到哈希集中并返回其大小。当处理高基数集和/或大值时,由于所需的内存使用量和节点之间的每个碎片集的通信需求将占用集群的太多资源,所以这不会扩大。
此基数聚合基于HyperlogLog++算法,该算法基于具有一些有趣属性的值的散列进行计数:
-
可配置的精度,决定了如何用内存换取精度
-
在低基数集上具有出色的精度,
-
固定内存使用:无论是否有数百或数十亿个唯一值,内存使用仅取决于配置的精度。
-
对于C的精度阈值,我们使用的实现需要大约C*8字节。
下表显示了阈值前后的错误变化情况:
对于所有3个阈值,计数精确到配置的阈值。虽然不能保证,但情况很可能是这样。实际的准确性取决于所讨论的数据集。一般来说,大多数数据集显示出一致的良好准确性。还要注意,即使阈值低至100,即使在计算数百万个项目时,误差仍然很低(如上图所示为1-6%)。
HyperlogLog++算法依赖于散列值的前导零,数据集中散列的精确分布会影响基数的准确性。
请注意,即使阈值低至100,即使在计算数百万个项目时,错误仍然很低。
预先计算的哈希
对于具有高基数的字符串字段,将字段值的哈希存储在索引中,然后在此字段上运行基数聚合可能会更快。这可以通过从客户端提供散列值来实现,也可以通过使用mapper-murmur3
插件让elasticsearch为您计算散列值。
注意:预计算散列通常只对非常大和/或高基数字段有用,因为它可以节省CPU和内存。但是,在数字字段上,哈希运算非常快,存储原始值所需的内存与存储哈希的内存差不多。在低基数字符串字段上也是如此,特别是考虑到这些字段具有优化功能,以确保每个段的唯一值最多计算一次哈希。
脚本
基数度量支持脚本编写,但由于需要动态计算散列值,因此性能会受到较大影响。
POST /sales/_search?size=0
{
"aggs" : {
"type_promoted_count" : {
"cardinality" : {
"script": {
"lang": "painless",
"source": "doc['type'].value + ' ' + doc['promoted'].value"
}
}
}
}
}
这将把脚本参数解释为具有无痛脚本语言且没有脚本参数的内联脚本。要使用存储的脚本,请使用以下语法:
POST /sales/_search?size=0
{
"aggs" : {
"type_promoted_count" : {
"cardinality" : {
"script" : {
"id": "my_script",
"params": {
"type_field": "type",
"promoted_field": "promoted"
}
}
}
}
}
}
缺省值
缺少参数定义如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。
POST /sales/_search?size=0
{
"aggs" : {
"tag_cardinality" : {
"cardinality" : {
"field" : "tag",
"missing": "N/A" <1>
}
}
}
}
-
标记字段中没有值的文档将与具有值N/A的文档属于同一个存储桶。