A register that became a list
A HyperLogLog is the strongest argument this collection has for approximation. Over a stream of forty thousand arrivals with 4,483 distinct keys, the exact answer needs a key per key — 143,456 bits — and the estimator needs two hundred and fifty-six five-bit registers, which is 1,280. A saving of a hundred and twelve times, for an answer wrong by about three per cent.
Ask the same estimator about the last 4,096 arrivals instead of about the whole stream. The exact structure now needs 52,290 bits and the estimator needs 9,722.
Five point four.
Nothing about the algorithm changed. What changed is the thing it is being compared against, and this essay is about why both structures move and why they move in opposite directions.
Why a register cannot be a number
The estimator’s whole mechanism is a maximum. Hash each key; look at the first few bits to choose a register; count the leading zeros of what is left and call that ; keep the largest any key hashing to that register has produced. A large is surprising, and the number of distinct keys is read off how surprising the most surprising hash was, as the essay that introduced it sets out.
A maximum over the whole stream is one number. A maximum over the last arrivals is not, and the reason is exactly one sentence: the largest may have arrived and left, and the structure has thrown away everything that would let it know what the second largest was.
The repair is due to Chabchoub and Hébrail, 2010, and it is the right one in the sense that it keeps precisely what is needed and nothing else. A register holds every arrival that could still become its maximum. An arrival makes every stored pair with a smaller or equal irrelevant — such a pair will expire no later and is no larger, so it can never be the answer again — and those are deleted.
The list’s length is bounded by the number of distinct values, so about twenty-five in the worst case, and in practice two or three. That bound is the reason the structure is viable at all: a register did not become an unbounded log of everything, it became a short list.
It is worth doing the arithmetic on why the lists stay short, because “bounded by the number of distinct values” is a worst case that never happens and the reason is a nice one. For the list to hold entries, the last arrivals at that register have to have arrived in strictly decreasing order of . The values are geometric — half of them are 1, a quarter are 2, an eighth are 3 — so a decreasing run of length three requires drawing three values in descending order from that distribution, and the probability falls fast. Averaged over a register’s live arrivals the expected length is a little under two, and the longest list in a structure of two hundred and fifty-six registers over forty thousand arrivals is typically four.
That is the same shape as the height of a skip list or the depth of a treap, and it has the same consequence: the structure’s size is a random variable whose mean is what gets quoted and whose tail is what a memory budget has to cover. The sizes reported here are the sizes at the moment they were measured, not expectations.
It also became mostly clocks. Five bits of against thirteen of stamp is the arithmetic the previous essay sets out, and it is why the estimator is the extreme case of the whole windowing problem — the part of it that is the answer is very small, so the part that is the time dominates.
The exact structure got cheap, and that is the larger half
The collapse looks at first like a failure of the estimator. It is mostly not.
The smallest exact windowed distinct-counter is a map from each key to the position of its most recent arrival. Nothing older is needed: a key is in the window exactly when its last arrival is, so one stamp per key answers the question, and a key that has expired can be deleted. That structure holds the distinct keys in the window rather than the distinct keys in the stream — and those are different numbers by a lot.
| stream | distinct, whole | distinct, in the window | exact bits | approximate bits | saving |
|---|---|---|---|---|---|
| stationary Zipf | 4,483 | 1,091 | 52,290 | 9,722 | 5.4× |
| one key floods a stretch | 4,320 | 1,091 | 52,290 | 9,704 | 5.4× |
| the popular keys drift | 1,561 | 169 | 8,505 | 3,944 | 2.2× |
The last row is the case a windowed distinct count exists for, and it is the case where approximation buys least. That is not a paradox: a stream whose popular keys drift has a small window cardinality, an exact structure holding a hundred and sixty-nine keys is not large, and there is not much for an estimator to save.
In the cash-register model the same three streams give savings of 112, 108 and 39 times. The ratio between the two models is between eighteen and twenty-one on all three, which is the more portable statement: windowing costs the estimator about twenty times its advantage, near enough independently of what the stream is doing.
Where the accuracy goes
The estimator still works. It is worth showing that before dwelling on what it costs, because a structure that had merely broken would produce the same collapse and would deserve a different essay.
| registers | bits | mean error | worst error |
|---|---|---|---|
| 32 | 1,348 | 13.4% | 26.0% |
| 64 | 2,012 | 7.0% | 19.8% |
| 128 | 2,872 | 3.0% | 10.9% |
| 256 | 3,944 | 4.3% | 7.2% |
| 512 | 5,494 | 3.0% | 9.1% |
The mean error is not monotone across the last three rows and it should not be expected to be: this is one stream scored at eight moments, and the standard error on eight samples of a quantity whose own standard deviation is is comfortably larger than the difference between 3.0% and 4.3%. The worst column, which is a maximum rather than a mean, falls at every step. Both are reported because reporting only the mean here would be reporting the flatter of two noisy measurements and calling it a trend.
The correction that is doing more work than usual
One detail deserves naming, because it changes which numbers above are about the estimator and which are about a patch on it.
At small cardinalities the raw HyperLogLog estimate is biased, and the standard repair is to switch to linear counting — read the answer off the number of registers that are still empty — whenever the raw estimate is below and any register is empty. Over a whole stream that regime is a brief phase at the beginning. Over a window it can be where the structure lives permanently, because the window’s cardinality is bounded by and by the drift, while is chosen for accuracy.
On the drifting stream the window holds a hundred and sixty-nine distinct keys and the plate above runs to five hundred and twelve registers. Three of those five points are in the linear-counting regime, and their accuracy is linear counting’s accuracy rather than HyperLogLog’s.
This is the same kind of observation as a bound that names its model: the accuracy claim usually quoted for HyperLogLog is , that claim is about the raw estimator in its own regime, and a structure asked about a window is often not in it. Choosing for a windowed estimator is therefore a choice about the window’s cardinality rather than about the stream’s, and it is a smaller number than the usual rule of thumb suggests.
What expiry costs to perform
Every number so far is a size, and this collection has a standing habit of asking whether the second count agrees with the first. Here it does not, and the direction is against the windowed structure again.
A cash-register HyperLogLog does one hash, one shift, one count of leading zeros and one comparison per arrival, and nothing else ever happens to it. Its work per item is a constant that does not depend on , on the window or on the data.
The windowed structure does the same hash, and then two things a maximum does not need. On the way in it walks the tail of its register’s list deleting the entries the new arrival dominates — cheap on average, since the lists are short, but it is a loop rather than a comparison. And on the way out something has to notice that the front of some list has expired. Expiry is not a per-register event; it is a per-structure event, and the honest implementation checks every register.
That check is what the measurements here charge nothing for. A structure that scans all registers on every arrival does times the work of the cash-register version, which at is not a constant factor anybody would ignore, and the standard repairs — expire lazily at query time, or keep the registers in a heap ordered by their front entry’s stamp — each cost something the size accounting above does not show. Lazy expiry means the structure is transiently larger than reported; a heap is another pointers.
So the size numbers in this essay are the smallest honest ones and the work numbers are absent, and a reader choosing between these structures should treat the second gap as real. It is the same disagreement between two counts that the machine field opened with, arriving in a place where only one of the two has ever been drawn.
The floor is not what moved
It would be tidy to say that the exact structure got cheap because there is less to know, and to leave it there. The lower bound says something more precise and worth having.
That bound is about a universe, not about a window, and it does not become smaller when the question does. What becomes smaller is the number of states the stream can actually reach: over a window of arrivals the set of possible answers is bounded by regardless of how large the universe is, so the exact structure never has to distinguish more than cases and typically distinguishes far fewer.
So the honest form of the collapse is: the window did not weaken the estimator, it strengthened the exact structure’s competitor position by bounding the problem. An approximation is worth what the exact answer costs, the exact answer over a window costs a fraction of what it costs over a stream, and a saving quoted in one model transfers to the other only after both structures have been re-weighed.
One list answers every shorter window too
There is a compensation for all of this that the accounting above does not credit the structure with, and it is large enough to change when the structure is worth building.
The list in a register holds every arrival that is not dominated — every pair whose is larger than everything after it. Ask for the maximum over the last arrivals rather than the last , and the answer is the front-most entry whose stamp is inside . That entry is in the list already: a pair inside the shorter window is dominated only by a later pair, and a later pair is also inside the shorter window, so the maximum over any sub-window is achieved by something the list kept.
So one structure answers every window length up to , at no extra state and no extra work. The query picks a cutoff and reads the front past it; the update rule does not change; nothing has to be decided in advance except the longest window anybody will ask about.
That is not a property the other windowed structures in this field have. An exponential histogram is built for one window length and cannot answer about a shorter one — its buckets have already merged away the resolution a shorter query would need — so a deployment wanting the last minute, the last hour and the last day keeps three of them and pays for all three. A register list wanting the same three keeps one, sized for the day.
Set that against the collapse this essay measures and the comparison moves. The windowed estimator loses a factor of twenty against the exact structure on a single window; against a deployment asking about several windows, the exact structure has to be replicated per window too — one map of keys to last-arrival stamps per window length, since a key can be in one window and not another. The estimator’s list is shared and the exact structure’s maps are not.
Which is the general shape worth carrying: a structure that keeps a non-dominated set rather than a summary is answering a family of questions rather than one. The extra state it holds over a plain maximum is exactly the state that makes the family available, and an accounting that prices it against a single question is charging it for something it is not doing.
The rule is the sliding-window maximum, per register
The domination rule is worth naming, because it is not specific to cardinality estimation and recognising it explains both the bound and the implementation.
Maintaining the maximum of the last elements of a sequence, as the window slides, is a standard problem with a standard answer: keep a deque of the elements that are not dominated — larger than everything after them — pushing at the back and popping from the front as things expire. Each element is pushed once and popped once, so the whole sweep is linear, and the deque’s contents are exactly the candidates for the maximum of any suffix.
That is precisely the structure inside each register here, with as the value and the arrival position as the time. The essay’s bound on the list length — the number of distinct values — is the deque’s bound applied to a small-alphabet sequence, and the observation two sections above that the deque answers every shorter window is the standard property of the same structure.
Naming it is worth the paragraph for a practical reason as well as a tidy one. The deque’s amortised argument is exactly the one that says the per-arrival work is despite the deletion loop — each entry is deleted once — so the loop the essay flags as “a loop rather than a comparison” is amortised constant, and the honest worry about per-item work is the expiry sweep across registers rather than the deletions within one.
What is not measured here
A sliding window over an unbounded universe with a bounded window is the easy case. Every measurement here has smaller than the number of distinct keys in the stream, so the exact structure genuinely benefits from expiry. Where the window is longer than the stream’s distinct count the exact structure is no smaller than it would be without a window, the estimator still pays its clocks, and the ratio is worse than any row in the table above. That regime is not drawn because it is not one anybody would build for, but a reader should know which side of it the numbers come from.
Merging. A cash-register HyperLogLog merges by taking the register-wise maximum, which is what makes it usable in a distributed system and is where a great deal of its value is. Two windowed structures merge by concatenating their lists and re-applying domination, which is correct and is not free, and the merged structure is larger than either. Nothing here measures it.
The other route. A windowed distinct count can also be built by keeping an exponential histogram per register rather than a list — trading exactness of the maximum for a bound on the list length. It is a different structure with a different error term, and quoting a size for it without building it would be quoting.
And the hash is assumed, here as everywhere. Every claim above rests on the hash turning whatever the keys are into something indistinguishable from random bits, and the windowed structure rests on it slightly harder than the cash-register one: a hash that maps a run of consecutive keys to a run of consecutive registers gives every register a contiguous stretch of arrivals rather than a scattering, and the lists’ behaviour under expiry is then a property of the key ordering rather than of the window. This collection has measured what a poor hash does to the unwindowed estimator and has not measured what it does to this one.
What this makes readable
Essays that name this one as a prerequisite.
Named alongside this one
Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.
- The count that outlives its arrivals expiry · honest limit · measurement · sliding window · state bits · timestamp · trade off
- The summary that has to forget expiry · measurement · sliding window · state bits · trade off
- The window that is even in the wrong currency expiry · measurement · sliding window · timestamp · trade off
- A decay measured from where it started honest limit · state bits · timestamp · trade off
- A promise about the rank is not a promise about the value honest limit · measurement · state bits · trade off
- An error measured against the answer honest limit · measurement · state bits · trade off
What links here
Every essay whose body links to this one.
The objects this essay names
Each one links to every other essay that touches it.
CardinalityDistinct countDominanceExpiryHash functionHonest limitHyperLogLogMeasurementSliding windowState bitsTimestampTrade off