Cumulative cardinality aggregation #
A parent pipeline aggregation reporting a running total of a
per-bucket distinct count — typically a cardinality metric —
answering “how many unique values have been counted up to and
including each bucket”.
"seen_so_far": {
"cumulative_cardinality": { "buckets_path": "buyers" }
}
How it works #
cumulative_cardinality is declared inside the multi-bucket
aggregation it decorates, next to the metric it consumes. The engine
walks the finished buckets in order and attaches the running total of
the referenced values under the pipeline’s own name — mechanically the
same accumulation as
cumulative_sum; only the
intended input (a per-bucket distinct count) differs.
That framing matters for correctness: the engine adds up the per-bucket counts; it does not union the distinct value sets across buckets (no sketch merge happens between buckets). Two consequences:
- Exact when buckets are disjoint — every distinct value appears
in at most one bucket. Buckets keyed by the value itself (a
termsagg over the same field you count distincts of), or one-off identifiers partitioned by period (unique order ids per day), are disjoint by construction. - It overcounts when a value recurs in several buckets. Per-day
buyer counts accumulate to more than the true number of distinct
buyers, because a buyer active on three days is counted three
times. A quick executed example: per-bucket distinct counts
2, 2, 1produce2, 4, 5, while the true running union is2, 3, 4.
Details verified against the engine:
buckets_pathaddresses acardinalitymetric (or any single-value metric) in the same bucket;"_count"accumulates document counts.- A bucket whose metric is missing answers
nulland the running total freezes, exactly ascumulative_sumdoes. - The sibling placement also works: declared next to the bucket
aggregation with
buckets_path: "per_day>buyers", it returns a standalone buckets array (keys0..n−1) with onevalueper consumed bucket.
Examples #
Read this one with the caveat above in mind. The teaching dataset
sells exactly once per day, so every bucket’s buyers is 1 and
seen_so_far climbs 1, 2, 3, … to 120 — while the whole index
holds only 4 distinct merchants, each active in many buckets. The
column is the accumulated per-day counts, not the running union.
Use cases #
- Disjoint-cohort counters — bucket documents by a cohort key (first-purchase month, signup week) and count distinct customers per cohort: each customer belongs to exactly one bucket, so the running column is the exact customer count to date.
- Unique-per-period identifiers — daily counts of distinct order or request ids, which by construction cannot span buckets, give an exact running volume of unique events.
- Growth of a partitioned vocabulary — terms per day over write-once keys (new SKUs, new nodes joining a cluster) accumulate correctly because a new key’s first appearance is its only one.
- A quick upper bound — even when values repeat across buckets, the column bounds the distinct count from above at every point, which can be enough for capacity signals.
Parameters for cumulative_cardinality
#
buckets_path
(Required, string) Path to acardinalitymetric in the same bucket.format
(Optional, string) Output number format. Accepted for compatibility; not applied to the value in the current engine.gap_policy
(Optional, string)skip(default) orinsert_zeros.
Related #
cumulative_sum— the same running accumulation over any per-bucket metriccardinality— the per-bucket distinct count this pipeline consumesderivative,serial_diff— the rest of the time-series family