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