| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 | [[search-aggregations-metrics-cardinality-aggregation]]=== Cardinality AggregationA `single-value` metrics aggregation that calculates an approximate count ofdistinct values. Values can be extracted either from specific fields in thedocument or generated by a script.Assume you are indexing books and would like to count the unique authors thatmatch a query:[source,js]--------------------------------------------------{    "aggs" : {        "author_count" : {            "cardinality" : {                "field" : "author"            }        }    }}--------------------------------------------------==== Precision controlThis aggregation also supports the `precision_threshold` and `rehash` options:experimental[The `precision_threshold` and `rehash` options are specific to the current internal implementation of the `cardinality` agg, which may change in the future][source,js]--------------------------------------------------{    "aggs" : {        "author_count" : {            "cardinality" : {                "field" : "author_hash",                "precision_threshold": 100, <1>                "rehash": false <2>            }        }    }}--------------------------------------------------<1> The `precision_threshold` options allows to trade memory for accuracy, anddefines a unique count below which counts are expected to be close toaccurate. Above this value, counts might become a bit more fuzzy. The maximumsupported value is 40000, thresholds above this number will have the sameeffect as a threshold of 40000.Default value depends on the number of parent aggregations that multiplecreate buckets (such as terms or histograms).<2> If you computed a hash on client-side, stored it into your documents and wantElasticsearch to use them to compute counts using this hash function withoutrehashing values, it is possible to specify `rehash: false`. Default value is`true`. Please note that the hash must be indexed as a long when `rehash` isfalse.==== Counts are approximateComputing exact counts requires loading values into a hash set and returning itssize. This doesn't scale when working on high-cardinality sets and/or largevalues as the required memory usage and the need to communicate thoseper-shard sets between nodes would utilize too many resources of the cluster.This `cardinality` aggregation is based on thehttp://static.googleusercontent.com/media/research.google.com/fr//pubs/archive/40671.pdf[HyperLogLog++]algorithm, which counts based on the hashes of the values with some interestingproperties: * configurable precision, which decides on how to trade memory for accuracy, * excellent accuracy on low-cardinality sets, * fixed memory usage: no matter if there are tens or billions of unique values,   memory usage only depends on the configured precision.For a precision threshold of `c`, the implementation that we are using requiresabout `c * 8` bytes.The following chart shows how the error varies before and after the threshold:image:images/cardinality_error.png[]For all 3 thresholds, counts have been accurate up to the configured threshold(although not guaranteed, this is likely to be the case). Please also note thateven with a threshold as low as 100, the error remains under 5%, even whencounting millions of items.==== Pre-computed hashesIf you don't want Elasticsearch to re-compute hashes on every run of thisaggregation, it is possible to use pre-computed hashes, either by computing ahash on client-side, indexing it and specifying `rehash: false`, or by usingthe special `murmur3` field mapper, typically in the context of a `multi-field`in the mapping:[source,js]--------------------------------------------------{    "author": {        "type": "string",        "fields": {            "hash": {                "type": "murmur3"            }        }    }}--------------------------------------------------With such a mapping, Elasticsearch is going to compute hashes of the `author`field at indexing time and store them in the `author.hash` field. Thisway, unique counts can be computed using the cardinality aggregation by onlyloading the hashes into memory, not the values of the `author` field, andwithout computing hashes on the fly:[source,js]--------------------------------------------------{    "aggs" : {        "author_count" : {            "cardinality" : {                "field" : "author.hash"            }        }    }}--------------------------------------------------NOTE: `rehash` is automatically set to `false` when computing unique counts ona `murmur3` field.NOTE: Pre-computing hashes is usually only useful on very large and/orhigh-cardinality fields as it saves CPU and memory. However, on numericfields, hashing is very fast and storing the original values requires as muchor less memory than storing the hashes. This is also true on low-cardinalitystring fields, especially given that those have an optimization in order tomake sure that hashes are computed at most once per unique value per segment.==== ScriptThe `cardinality` metric supports scripting, with a noticeable performance hithowever since hashes need to be computed on the fly.[source,js]--------------------------------------------------{    "aggs" : {        "author_count" : {            "cardinality" : {                "script": "doc['author.first_name'].value + ' ' + doc['author.last_name'].value"            }        }    }}--------------------------------------------------This will interpret the `script` parameter as an `inline` script with the default script language and no script parameters. To use a file script use the following syntax:[source,js]--------------------------------------------------{    "aggs" : {        "author_count" : {            "cardinality" : {                "script" : {                    "file": "my_script",                    "params": {                        "first_name_field": "author.first_name",                        "last_name_field": "author.last_name"                    }                }            }        }    }}--------------------------------------------------TIP: for indexed scripts replace the `file` parameter with an `id` parameter.==== Missing valueThe `missing` parameter defines how documents that are missing a value should be treated.By default they will be ignored but it is also possible to treat them as if theyhad a value.[source,js]--------------------------------------------------{    "aggs" : {        "tag_cardinality" : {            "cardinality" : {                "field" : "tag",                "missing": "N/A" <1>            }        }    }}--------------------------------------------------<1> Documents without a value in the `tag` field will fall into the same bucket as documents that have the value `N/A`.
 |