# 基数聚合(Cardinality Aggregation)

single-value度量聚合就是计算单值的近似值。这些值可以从文本中获取或者使用脚本生成。

假设你正在建立书的索引，并且希望请求与作者唯一匹配：

```
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "field" : "author"
            }
        }
    }
}
```

## Precision Control

这个聚类操作支持precision\_threshold选项：

> 警告：precision\_threshold选项特定于当前内部实现的cardinality agg，它可能会在以后进行修改。

```
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "field" : "author_hash",
                "precision_threshold": 100
            }
        }
    }
}
```

precision\_threshold选项允许交易内存的准确性，并定义一个唯一的计数，低于该计数预计接近准确。 高于这个值，计数可能会变得更模糊。 支持的最大值为40000，超过此数字的阈值将具有与阈值40000相同的效果。默认值为3000。

## Counts are approximate

计算精确计数要求加载值到一个哈希集并返回它的大小，当工作在高基数时需要占用大量的内存空间，同时在节点间沟通每个分片集也会占用大量的集群资源，所以计算的效率是比较低的。

基数聚合基于[HyperLogLog++](http://static.googleusercontent.com/media/research.google.com/fr/pubs/archive/40671.pdf) 算法，这个算法基于散列值，它有以下这些有趣的性质：

* 可配置的精度，它决定为了准确性如何交换内存；
* 低基数集的优良精度；
* 固定内存使用：无论有几十或数十亿的唯一值，内存的使用仅取决于配置的精度。

对于c的精确阈值，我们的实现需要使用大约8字节。

下图显示了设置阈值前后误差如何变化：![](https://www.elastic.co/guide/en/elasticsearch/reference/current/images/cardinality_error.png)

对于所有3个阈值，计数已准确到配置阈值（虽然没有保证，这是可能的情况下）。请注意，即使有一个阈值低至100，错误仍然非常低，即使是数以百万计数据。

## Pre-computed hashes

在具有高基数的字符串字段中，在索引中存储字段值的哈希值可能更快，然后在该字段中运行基数聚合。可以在客户端计算出哈希值（再提供给es），也可以让elasticsearch使用[`mapper-murmur3`](https://www.elastic.co/guide/en/elasticsearch/plugins/5.3/mapper-murmur3.html)插件为你计算出哈希值。

> 预计算哈希值通常仅适用于非常大的和/或高基数字段，这样可以节省CPU和内存。然而，对于数字字段，计算哈希是非常快速的，存储原始的值需要的内存比存储计算出的哈希值可能更多也，可能更少（差不多，所以没必要使用预计算哈希值）。对于低基数字符串字段也是这样，特别是在那些优化确保每一段数据哈希值保持唯一值的情况下（也没必要使用预计算哈希值）。

## Script

基数聚合支持使用脚本，但是使用脚本会带来明显的性能损失：

```
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "script": {
                    "lang": "painless",
                    "inline": "doc['author.first_name'].value + ' ' + doc['author.last_name'].value"
                }
            }
        }
    }
}
```

上面的语句将会使用系统内置的脚本语言进行解释，而且是不带参数的。用一个文件脚本的完整语法如下：

```
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "script" : {
                    "file": "my_script",
                    "params": {
                        "first_name_field": "author.first_name",
                        "last_name_field": "author.last_name"
                    }
                }
            }
        }
    }
}
```

> 对于索引脚本只需要将file参数替换为id参数。

## Missing Value

Missing字段定义了文档缺失值的时候应该如何处理。默认情况下这些文档会被忽略，但是也可以认为它们有一个默认的值存在：

```
{
    "aggs" : {
        "tag_cardinality" : {
            "cardinality" : {
                "field" : "tag",
                "missing": "N/A"
            }
        }
    }
}
```

> 如果文档没有tag字段，则认为该文档的tag值为“N/A”。
