Streaming Sketches
Sampling and counting kept a random subset or a single approximate tally. Sketches go further: fixed, tiny summaries that answer questions about a stream's frequencies.
╌╌╌╌
This builds on Data-Stream Algorithms, which set up the streaming model and its exactness-for-space trade-off, then applied it to two problems: keeping a uniform sample with reservoir sampling, and keeping an approximate count with Morris counting. Both summarized the stream as a whole. This lesson asks harder questions about the contents of the stream, how often a given item occurred, which items are frequent, and how many distinct items there were, and answers each with a sketch: a small array of counters, updated by hashing, whose size is fixed in advance and never grows with the stream. As before the tools are hashing and randomized analysis, and as before the answers are approximate, with an error set by choosing the sketch's dimensions.
Count–Min sketch: frequency estimation in a grid
Problem. Over a stream of items drawn from a huge universe, estimate the frequency of any queried item using space far smaller than the number of distinct items.
Idea. Keep a small grid of counters with rows and columns. Equip each row with its own hash function mapping items into . To record an item, bump one counter per row, the cell its row's hash selects. Collisions only ever add to a counter, so each row gives an overestimate of the true frequency; taking the minimum across the rows keeps the tightest one.
The update and query are both a handful of hashes; the whole structure is one array of integers.
- 1procedurerecord one occurrence of item
- 2for to do
- 3bump one cell per row
- 4procedureestimate the frequency of
- 5
- 6for to do
- 7tightest row wins
- 8return
A worked trace. Take a tiny sketch with rows and columns, and hash functions given by the table
Feed it the ten-item stream , so the true frequencies are , , , . Each arrival bumps cell in row and cell in row . Row accumulates 's three occurrences in column , 's four plus 's two in the shared column , and 's single occurrence in column . Row piles and together in column , puts in column , and keeps alone in column .
The two queries show both cases. Row happened to give a private cell, so the minimum returns the exact count . Item shares a cell with in row and with in row , so both estimates are inflated and even the minimum, , is more than double the true count . This is the general pattern: heavy items are estimated well because their own mass dominates their cells, while rare items are swamped by whatever collides with them.
Why take the minimum: every row's counter for equals 's true count plus whatever other items collided into the same cell. Collisions never subtract, so always, and the minimum is the row with the least colliding mass.
Choosing the grid. The parameters translate directly into memory. For a additive error () with confidence (): columns and rows, about counters, some KB of -byte cells. That footprint is fixed no matter whether the stream carries thousands of items or trillions, and no matter how many distinct items appear; only the guarantee's noise floor scales with the stream.
The error is one-sided (always an overestimate) and additive in the stream length, so Count–Min is most accurate for the frequent items whose true counts dwarf the noise floor, exactly the items one usually cares about. Two practical footnotes. First, the sketch answers point queries only: it cannot list the frequent items by itself, because the universe is too large to query exhaustively; pair it with a heap of the top candidates seen so far, or with Misra–Gries below, when you need the list. Second, a small tweak called conservative update increments, on each arrival, only those of the item's counters that equal the current minimum; every row still upper-bounds the truth, and collisions inflate the cells more slowly. Count–Min is used in network flow monitoring, trending-term counts, and database query-frequency statistics.
Misra–Gries: heavy hitters in counters
Problem. Find the heavy hitters, every item whose frequency exceeds an fraction of the stream, without storing all distinct items.
Idea. Keep at most labelled counters, where . For each arriving item: if it already holds a counter, increment it; if a counter is free, claim it at ; otherwise decrement every counter, dropping any that hit zero. The decrement pairs occurrences off: each new unmatched item cancels one occurrence of others, so an item can keep a counter only if it appeared often enough to absorb the cancellations.
- 1empty mapat most labelled counters
- 2for each item do
- 3if then
- 4already holds a counter
- 5else if then
- 6a counter is free: claim it
- 7elsetable full, unmatched: decrement round
- 8for each label in do
- 9
- 10if then remove fromevict at zero
- 11returncandidates with estimates
A worked trace. Run Misra–Gries with counters (, so ) on the seven-item stream , where , , .
- — table empty, claim a counter: .
- — one counter free, claim it: .
- — matched, increment: .
- — unmatched, table full: decrement all. drops to , drops to and is evicted; itself is not stored: .
- — matched, increment: .
- — counter free again, claim it: .
- — matched, increment: , with alongside.
The final table reports and against the truth , . Both are under-reported by exactly , the number of decrement rounds, and the theorem below says that number can never exceed . The heavy hitter (frequency ) survived, as it must; survived too, a false positive the guarantee permits.
Each surviving counter under-reports by at most the number of decrement rounds, which is bounded because each round consumes distinct arrivals.
From candidates to answers. The guarantee runs one way: no false negatives among the true heavy hitters, but false positives are possible, as in the trace shows. When exact confirmation matters and the data can be replayed, a second pass over the stream counts only the surviving candidates exactly. In a strict one-pass setting, a Count–Min sketch running alongside serves as the verifier: Misra–Gries produces the candidates, Count–Min estimates their counts. The two sketches are complementary in their bias as well, Misra–Gries never overestimates and Count–Min never underestimates, so together they bracket the truth.
The special case is the classic majority vote algorithm: one counter, incremented on a match, decremented on a mismatch, and whatever survives is the only possible majority element. Misra–Gries is the general- version of that pairing-off argument, and the standard answer to find the trending hashtags / the top talkers on a link.
HyperLogLog: counting the distinct
Problem. Estimate the number of distinct items in a stream, the cardinality, in a few kilobytes, even when there are billions of distinct values.
Storing a set or a hash table to deduplicate would cost space, exactly what we cannot afford. HyperLogLog instead reads cardinality off a statistic that is invariant to duplicates: the longest run of leading zeros seen among the items' hash values.
Idea. Hash each item to a uniform bit string and look at the position of its first bit, equivalently the number of leading zeros, . A leading run of zeros occurs with probability , so seeing a maximum run of length across the stream suggests roughly distinct values were hashed, duplicates don't matter, since a repeated item hashes to the same string and contributes no new zeros.
A single max-zero count is far too noisy, its variance is enormous: one unluckily long run of zeros, from a single hash value, doubles or quadruples the estimate, and more stream data cannot correct it, because the maximum never decreases. The repair has two parts.
Buckets and the harmonic mean. Split the sketch into buckets and give each bucket its own maximum. One hash serves both roles: the first bits of choose the bucket , and the remaining bits supply the statistic , the position of the first bit (one more than the count of leading zeros). Each bucket keeps a small register over the items routed to it, so the sketch as a whole is independent estimates produced by a single pass and a single hash per item.
- 1one register per bucket
- 2for each item do
- 3uniform bit string
- 4first bits pick a bucket
- 5position of first bit in
- 6registers only ever grow
- 7returnharmonic combination
The estimator combines the registers by a harmonic mean: the raw estimate is
where is a bias-correction constant that tends to as grows. The harmonic mean is the right average precisely because of the outlier problem: each is a per-bucket cardinality guess whose distribution has a heavy upper tail, and an arithmetic mean would let one outlier register drag the whole estimate up. The harmonic mean works on reciprocals, where an outlier contributes a term near zero instead of a huge one, so single outliers are damped rather than amplified. Averaging across the buckets then shrinks the relative standard error to about .
A small example. With buckets (far too few in practice, the right size for arithmetic by hand), suppose a run leaves the registers at . Then
a sensible reading for a run in which roughly a dozen distinct values were hashed. Each register only needed to store a number no larger than the hash length, so to bits per bucket suffice for -bit hashes.
Range corrections. Two regimes need care. When the true cardinality is small compared to , many buckets are still empty () and the raw formula biases high; the fix is to count the empty buckets and switch to the linear counting estimate , which reads cardinality off the emptiness rate instead. At the far top of the range, hash collisions in a -bit hash space compress the estimate, which either a correction term or, in modern implementations, a -bit hash makes moot.
This is the structure behind COUNT(DISTINCT ...) approximations in analytics
databases and unique-visitor counts at web scale: a fixed, tiny footprint that
counts distinct items without storing them.
The register semantics also make the sketch mergeable: since registers only take
maxima, two HyperLogLog sketches built on different machines merge by a
pointwise , giving the sketch of the combined stream — which is why it
distributes so well.
Sketches in the wild
All three sketches run in production at scale, and each has later refinements worth knowing.
The Count–Min sketch is due to Cormode and Muthukrishnan (2005), and its
conservative update variant, incrementing on each arrival only the counters
that currently equal the item's minimum, comes from Estan and Varghese's
network-measurement work. Databases use it and its relatives for query
planning: Apache Spark, for instance, exposes CountMinSketch directly, and the
same idea underlies the frequency statistics a query optimizer keeps to guess
join selectivities. A close cousin, the count sketch of Charikar, Chen, and
Farach-Colton (2002), hashes each item to as well as to a bucket, which
makes its estimate unbiased rather than one-sided, useful when frequencies
must be summed and subtracted.
Misra–Gries (1982) is the ancestor of the two heavy-hitter algorithms most
deployed today, Space-Saving (Metwally, Agrawal, El Abbadi, 2005) and
Lossy Counting (Manku and Motwani, 2002). Space-Saving keeps the same
counters but, instead of decrementing everyone on an
overflow, overwrites the current minimum counter with the new item and inherits
its count, which tends to track the true frequencies more tightly. These power
the trending now
and top talkers
panels of large systems where storing
per-item state is out of the question.
HyperLogLog (Flajolet, Fusy, Gandouet, Meunier, 2007) refined Durand and
Flajolet's LogLog, which itself descended from the Flajolet–Martin sketch of
1985. The practically important sequel is Google's HyperLogLog++ (Heule,
Nunkesser, Hall, 2013), which adds a 64-bit hash, a bias-corrected small-range
estimate, and a sparse representation for low cardinalities; it is what backs
APPROX_COUNT_DISTINCT in BigQuery and the PFCOUNT command in Redis. The
mergeability that makes HyperLogLog distribute, two sketches combine by a
pointwise maximum, is what lets these systems shard a cardinality count
across machines and recombine the pieces exactly.2
Where these sketches live, and the takeaway
Each sketch answers a different question about a stream's contents, and the choice among them starts from the question:
| question about the stream | technique | space | guarantee |
|---|---|---|---|
| how often did item occur? | Count–Min sketch | counters | w.p. |
| which items are frequent? | Misra–Gries | counters | , deterministic |
| how many distinct items? | HyperLogLog | bits | relative error |
Two contrasts in that table matter. Misra–Gries is the only
deterministic guarantee, no hashing, no failure probability, but it answers
only who is frequent,
while Count–Min answers arbitrary point queries at the
price of randomness. And the two frequency sketches err in opposite directions,
under versus over: Misra–Gries never overestimates and Count–Min never
underestimates, so running both brackets the truth, a standard move when you
need a two-sided guarantee from one-sided tools.
All three share the pattern from Morris counting in the previous lesson: a small random summary standing in for a quantity too large to store exactly, made accurate by structure — averaging across rows in Count–Min, cancellation in Misra–Gries, harmonic averaging across buckets in HyperLogLog. Databases keep Count–Min and HyperLogLog statistics to plan queries without scanning whole tables; routers run Misra–Gries and Count–Min to spot heavy flows at line rate; analytics pipelines use HyperLogLog for unique-visitor counts over unbounded clickstreams. Each fixes its footprint in advance and accepts a small, tunable error in return.
Takeaways
- A sketch is a fixed-size summary of a stream, updated by hashing, whose space is chosen in advance and never grows with the stream; the price is an approximate, usually probabilistic, answer.
- The Count–Min sketch estimates frequencies in a counter grid; its error is one-sided () and additive, with probability , by a Markov-plus-independence argument across rows. It is most accurate for the heavy items whose own mass dominates their cells.
- Misra–Gries finds heavy-hitter candidates in counters with the deterministic sandwich ; each decrement round consumes stream items, so there are at most rounds. The case is the classic majority-vote algorithm.
- HyperLogLog estimates distinct counts from per-bucket maximum leading-zero statistics combined by a harmonic mean, with relative error in a few kilobytes, and merges across machines by a pointwise .
- The two frequency sketches err in opposite directions, so running both brackets the truth; Misra–Gries alone is the only fully deterministic guarantee of the three.
Footnotes
- CLRS, App. C — Counting and Probability: the expectation, Markov-inequality, and union-bound arguments behind the Count–Min and Misra–Gries guarantees. ↩
- Cormode & Muthukrishnan,
An improved data stream summary: the count-min sketch
(2005); Metwally, Agrawal & El Abbadi,Efficient computation of frequent and top-k elements
(Space-Saving, 2005); Flajolet, Fusy, Gandouet & Meunier,HyperLogLog
(2007); Heule, Nunkesser & Hall,HyperLogLog in practice
(HyperLogLog++, 2013). ↩
╌╌ END ╌╌