One pass, and no room

An error measured against the answer

A quantile summary asked for the 99.9th percentile answered 9,694 where the truth was 256, and violated nothing — its promise was a rank error under one per cent of the stream and it delivered a tenth of one per cent. One per cent of the stream is a thousand per cent of the tail, and no amount of extra state changes that.

The measurement this collection has already made, restated so that what follows is about a repair rather than about a complaint.

A Greenwald–Khanna summary at ε=0.01\varepsilon = 0.01 is asked for the 99.9th percentile of forty thousand heavy-tailed values. It answers 9,693.8, which is the largest value that ever arrived. The truth is 255.7.

Nothing was violated. Its promise is that the returned value’s rank is within εn\varepsilon n of the rank asked for; the rank asked for is 39,960, the rank of 9,693.8 is 40,000, and the difference is 40 out of 40,000 — a rank error of a tenth of one per cent, well inside a promise of one per cent.

The value is off by a factor of thirty-eight.

One query — the 0.999 quantile — answered by 3 summariesThe true 0.999 quantile of 40,000 Pareto values is 256, marked by the line. Each bar is what a summary answered. Greenwald–Khanna says 9,694 — a rank error of 0.100% of the stream, which is 100.0% of the tail, and a value error of 3691.8%; high-biased says 256 — a rank error of 0.000% of the stream, which is 0.0% of the tail, and a value error of 0.0%; t-digest says 546 — a rank error of 0.060% of the stream, which is 60.0% of the tail, and a value error of 113.7%. Every one of these is inside whatever it promised, where it promised anything. The numbers a reader would act on differ by more than an order of magnitude.Greenwald–Khanna7,104 bits9,694high-biased55,680 bits256t-digest5,952 bits546the truth, 256ε = 0.01, δ = 100 · 40,000 valuesq = 0.999
Fig. 1 One query, three summaries, and the truth marked. Two of these are inside a stated promise and one has no promise at all; the numbers a reader would act on differ by more than an order of magnitude.

The promise is measured against the wrong thing

The diagnosis is arithmetic and it fits in two lines.

The promise is εn\varepsilon n — a fraction of the whole stream. The quantile asked for is about the top (1q)n(1-q)n items. So the promise, expressed as a fraction of the thing the question is about, is

εn(1q)n=ε1q\frac{\varepsilon n}{(1-q)n} = \frac{\varepsilon}{1-q}

At the median that is 2ε2\varepsilon: the promise is twice as tight as the question is broad, which is fine. At q=0.99q = 0.99 it is 100ε100\varepsilon. At q=0.999q = 0.999 it is 1,000ε1{,}000\varepsilon, which at ε=0.01\varepsilon = 0.01 is ten times the entire tail — a permission to return any of the top ten thousandths of the data, and there are only forty of them.

Rank error as a fraction of the whole streamRank error against the whole stream, which is the quantity every one of these summaries states its promise in. On this plate they all look accurate and the differences between them look small, which is the honest picture of what the guarantees say and is not the picture of what a reader of a tail percentile gets. The vertical axis is logarithmic.0.001%0.01%0.1%0.50.750.90.990.999quantile asked forrank error ÷ nGreenwald–Khanna7,080 bitshigh-biased56,064 bitst-digest5,952 bits8 streams per point · ε = 0.01, δ = 100denominator: the stream
Fig. 2 The measurement everybody makes: rank error as a fraction of the stream, averaged over eight independent streams. Every summary looks accurate, all the lines are flat, and the differences between them look like implementation noise. This is an honest plot of what the guarantees say.
Rank error as a fraction of the tail it is aboutThe same measurements as a plate reporting error against the stream, divided by the mass the quantile is about — 1 − q, which is a half at the median and a thousandth at q = 0.999. Averaged over 8 independent streams of 40,000 Pareto values. A relative promise is a flat line on this plate and an absolute one climbs, because the numerator is constant and the denominator is shrinking. Greenwald–Khanna: 0.64% → 1.37% → 3.63% → 47% → 100%; high-biased: 0.46% → 0.42% → 0.44% → 0.56% → 0.00%; t-digest: 0.33% → 0.50% → 1.15% → 11% → 56%. The vertical axis is logarithmic.0.1%1%10%100%0.50.750.90.990.999quantile asked forrank error ÷ (1 − q)Greenwald–Khanna7,080 bitshigh-biased56,064 bitst-digest5,952 bits8 streams per point · ε = 0.01, δ = 100denominator: the tail
Fig. 3 The same measurements divided by the mass the quantile is about. A relative promise is a flat line on this plate and an absolute one climbs, because the numerator is fixed and the denominator is shrinking. Nothing changed but the denominator.
quantile Greenwald–Khanna high-biased t-digest
0.5 0.64% 0.46% 0.33%
0.75 1.37% 0.42% 0.50%
0.9 3.63% 0.44% 1.15%
0.99 47.28% 0.56% 10.91%
0.999 100.00% 0.00% 55.62%

The last row of the first column is exactly one hundred per cent, and it is exact for a reason: the answer is the maximum. Out in a tail there are few items per unit of value, so a tuple can absorb a wide stretch of the value range while absorbing few enough items to stay under the cap — and the value a merged tuple keeps is the right-hand one. Applied repeatedly across the top, the surviving representative of everything above a point is the largest thing seen.

More state does not help

This is the part that makes it a defect in the shape of the promise rather than a budget problem.

Rank error at q = 0.999, as a fraction of the tail, against bitsEach point is one summary at one setting, averaged over 8 independent value streams of 40,000 draws — averaged because a far-tail rank error is a measurement over a handful of items and wanders by tens of per cent from one stream to the next. The vertical axis is the rank error divided by the mass the quantile is about, which is the number a reader of the 0.999 percentile cares about; measured against the whole stream instead, every one of these summaries looks accurate. Greenwald–Khanna runs from 100.0% at 1,500 bits to 100.0% at 14,208; high-biased runs from 1.2% at 12,816 bits to 0.0% at 103,260; t-digest runs from 49.1% at 2,976 bits to 2.5% at 49,140. Both axes are logarithmic.10,000100,0000.0000010.000010.00010.0010.010.11bits of state heldrank error ÷ tail mass at q = 0.999Greenwald–Khannahigh-biasedt-digest8 streams per point · truth held apartq = 0.999, tail mass 0.001
Fig. 4 Tail-relative rank error at the 99.9th percentile against bits of state, averaged over six streams. One of these lines is flat at one hundred per cent across a tenfold increase in state.
Greenwald–Khanna at bits error, as a share of the tail
ε=0.05\varepsilon = 0.05 1,536 100%
ε=0.02\varepsilon = 0.02 3,440 100%
ε=0.01\varepsilon = 0.01 7,088 100%
ε=0.005\varepsilon = 0.005 14,144 100%

Nine times the state, and the answer at q=0.999q = 0.999 is the maximum every time. The reason is that the invariant caps every tuple’s uncertainty at 2εn2\varepsilon n wherever it sits, so tightening ε\varepsilon tightens the cap everywhere equally — and at q=0.999q = 0.999 with n=40,000n = 40{,}000 the tail is forty items, so the cap has to fall below forty before anything at all changes. At ε=0.005\varepsilon = 0.005 it is four hundred.

A structure whose accuracy parameter cannot reach the region being asked about is not inaccurate. It is answering a different question.

The repair is one line of the invariant

Cormode, Korn, Muthukrishnan and Srivastava, in 2005, make the cap a function of where the tuple sits rather than a constant:

  • f(r,n)=2εnf(r, n) = 2\varepsilon n — Greenwald–Khanna. The same cap everywhere.
  • f(r,n)=2ε(nr)f(r, n) = 2\varepsilon (n - r)high-biased. A tuple at rank rr may be uncertain by ε\varepsilon times the mass above it, so the promise at qq is ε(1q)n\varepsilon(1-q)n and the tail is answered to within ε\varepsilon of the tail.
  • f(r,n)=2εrf(r, n) = 2\varepsilon r — low-biased, the mirror image, for distributions whose interesting end is the small one.

Everything else — the tuple representation, the compression pass, the query — is unchanged. It is the same code with a different right-hand side, which is why the implementation here is one class with the rule as a parameter and the three settings share every line of machinery. A comparison built from two independent implementations would be a comparison of two authors as much as of two invariants.

One detail is not cosmetic: the high-biased cap goes to zero at the very top of the distribution, and a cap of zero means no tuple up there may ever merge, so the summary keeps one tuple per arrival and is not a summary. The floor here is one item — a tuple whose uncertainty is under a single item is exact, and there is nothing to be gained by demanding less.

Where each summary keeps its stored valuesEvery stored value in each summary, placed at the quantile it sits at in the data — 40,000 draws from a Pareto distribution. Greenwald–Khanna keeps 74 of them in 7,104 bits; high-biased keeps 580 of them in 55,680 bits; t-digest keeps 62 of them in 5,952 bits. Greenwald–Khanna spreads them evenly, because its invariant caps every tuple's uncertainty at the same fraction of the stream wherever it sits. The biased summary crowds them into the top, because its cap there is a fraction of a tail that is itself small — and that crowding is exactly what the extra bits bought. The digest's spacing comes from an arcsine, which is dense at both ends and sparse in the middle, and it is a rule about shape rather than a promise about error.Greenwald–Khanna74 kept · 7,104 bitshigh-biased580 kept · 55,680 bitst-digest62 kept · 5,952 bits00.50.91quantile of the dataε = 0.01, δ = 100 · 40,000 values74 / 580 / 62 stored values
Fig. 5 Where each summary keeps its stored values, placed at the quantile they sit at in the data. Greenwald–Khanna spreads them evenly, because its cap is the same everywhere. The biased summary crowds them into the top, because its cap there is a fraction of a tail that is itself small. The crowding is what the extra bits bought.

Where the cap actually acts

The invariant is worth watching in operation, because “make the cap a function of rank” hides where the work happens.

Every tuple carries three numbers: a value, gg — how many items it stands for — and δ\delta — how much uncertainty there is about where the run it stands for begins. The compression pass walks the summary and merges a tuple into its right-hand neighbour whenever

gi+gi+1+δi+1f(ri,n)g_i + g_{i+1} + \delta_{i+1} \le f(r_i, n)

so a large cap permits large merges and a small cap permits none. Under the uniform rule that inequality has the same right-hand side at every position, so the pass merges greedily and evenly and the summary ends up with tuples of roughly equal weight spread across the distribution — which is what the tuple plate above shows.

Under the high-biased rule the right-hand side falls to almost nothing at the top. A tuple sitting at rank rr near nn is allowed 2ε(nr)2\varepsilon(n-r) of uncertainty, which for the last few hundred items is under one, so those tuples never merge with anything and the top of the distribution is stored item by item. That is not an approximation at all up there; it is a sorted list of the largest few hundred values, arrived at without anybody deciding how many to keep.

Which is a useful way to think about what the extra bits bought. The biased summary is a uniform summary of the bulk with an exact record of the extreme, and the crossover between the two regimes is wherever 2ε(nr)2\varepsilon(n-r) falls below one — at ε=0.01\varepsilon = 0.01 and n=40,000n = 40{,}000, the top fifty items.

And that is why more state cannot rescue the uniform rule. Tightening ε\varepsilon moves a uniform summary’s resolution everywhere at once, which is the expensive way to buy resolution in one place. The biased rule buys it where it is needed and pays uniform prices everywhere else.

The floor is a choice and it is stated

One number in the implementation is not in the published rule, and it deserves naming because a reader reproducing this would hit it in the first minute.

The high-biased cap is 2ε(nr)2\varepsilon(n-r), which is zero at r=nr = n. A cap of zero forbids every merge at the very top, and a summary that never merges at the top keeps one tuple per arrival there — but the top moves as the stream runs, so in practice it keeps one tuple per arrival, full stop, and is not a summary.

The floor used here is one item: no tuple’s cap is ever below one, on the grounds that a tuple whose uncertainty is under a single item is already exact and there is nothing to buy by demanding less. It is stated in the code and it is stated here because it is the difference between a structure that summarises and one that does not, and it is not in the invariant as published.

That is the same kind of gap as the half-bucket rule in the windowed histogram: a published estimate that is right in the regime the analysis is about and wrong at the boundary, where the structure is keeping things exactly and charging itself for uncertainty it does not have.

What it costs

Eight times the state, on these streams: 55,680 bits against 7,104, 580 stored tuples against 74.

That is a real price and the shape of it is worth understanding rather than quoting. Greenwald–Khanna keeps O(1εlogεn)O(\frac{1}{\varepsilon}\log \varepsilon n) tuples because the cap is uniform and the summary can be uniform to match. The high-biased summary needs the tail resolved to ε(1q)n\varepsilon(1-q)n for every qq, and summing that requirement across the distribution costs another logarithm.

But the comparison at equal ε\varepsilon is the wrong one, because the two values of ε\varepsilon mean different things. The honest comparison is at equal bits, and the plate above does it: at 14,144 bits Greenwald–Khanna answers the far tail with the maximum, and the biased summary at 12,800 bits answers it to within 0.8% of the tail. There is no budget in the range measured at which the uniform cap is the better use of the space, for a tail question.

For a median question it is the other way and by a wide margin, which is the sentence the plate above should not be allowed to hide. At q=0.5q = 0.5 both are around half a per cent of the tail and one of them costs an eighth as much.

Rank error at q = 0.99, as a fraction of the tail, against bitsEach point is one summary at one setting, averaged over 8 independent value streams of 40,000 draws — averaged because a far-tail rank error is a measurement over a handful of items and wanders by tens of per cent from one stream to the next. The vertical axis is the rank error divided by the mass the quantile is about, which is the number a reader of the 0.99 percentile cares about; measured against the whole stream instead, every one of these summaries looks accurate. Greenwald–Khanna runs from 100.0% at 1,500 bits to 11.7% at 14,208; high-biased runs from 2.4% at 12,816 bits to 0.2% at 103,260; t-digest runs from 34.4% at 2,976 bits to 0.4% at 49,140. Both axes are logarithmic.10,000100,0000.010.11bits of state heldrank error ÷ tail mass at q = 0.99Greenwald–Khannahigh-biasedt-digest8 streams per point · truth held apartq = 0.99, tail mass 0.01
Fig. 6 The same trade one quantile in, at the 99th percentile, where the uniform cap is not yet hopeless — it improves with state here, from 34% of the tail down to 5%, while the biased summary is under one per cent at every budget.

The other end, for free

The same machinery with the cap mirrored answers the head of a distribution to a relative tolerance, which is the case where somebody cares about the fastest requests, the smallest orders, the shortest sessions.

quantile Greenwald–Khanna low-biased
0.001 0.0975% 0.0000%
0.01 0.3706% 0.0034%
0.1 0.5222% 0.0347%
0.5 0.3175% 0.2112%

Those are rank errors as a fraction of the stream, not of the head — the fair comparison at the low end, and the biased summary is between thirty and a hundred times tighter for a similar price. Both promises are legitimate; only one of them is about the question.

Where each summary keeps its stored valuesEvery stored value in each summary, placed at the quantile it sits at in the data — 40,000 draws from a Pareto distribution. Greenwald–Khanna keeps 74 of them in 7,104 bits; high-biased keeps 580 of them in 55,680 bits; low-biased keeps 589 of them in 56,544 bits. Greenwald–Khanna spreads them evenly, because its invariant caps every tuple's uncertainty at the same fraction of the stream wherever it sits. The biased summary crowds them into the top, because its cap there is a fraction of a tail that is itself small — and that crowding is exactly what the extra bits bought. The digest's spacing comes from an arcsine, which is dense at both ends and sparse in the middle, and it is a rule about shape rather than a promise about error.Greenwald–Khanna74 kept · 7,104 bitshigh-biased580 kept · 55,680 bitslow-biased589 kept · 56,544 bits00.50.91quantile of the dataε = 0.01, δ = 100 · 40,000 values74 / 580 / 589 stored values
Fig. 7 The three caps, drawn as where they put their tuples. The mirror image is exactly a mirror image, which is worth seeing because it makes clear that neither end is special — the summary is dense wherever its cap is small, and the cap is a line of arithmetic.

The rank error cannot see the values, and that is provable

There is a stronger statement available about why the rank error was so misleading, and it is the one to carry away.

Greenwald–Khanna and the biased summary touch the data with <= and with nothing else. Every merge decision, every tuple boundary, every answer’s position in the sorted order is a function of the ranks alone. So relabel the values by any strictly increasing function — take the exponential of every one of them, say — and the structure that results is identical, tuple for tuple.

Measured: the rank errors are the same to the last digit.

q=0.5q = 0.5 q=0.9q = 0.9 q=0.99q = 0.99 q=0.999q = 0.999
rank error, original values 0.00300 0.00265 0.00685 0.00100
rank error, exponentiated 0.00300 0.00265 0.00685 0.00100
value error, original 0.7% 0.3% 0.6% 0.1%
value error, exponentiated 5.9% 5.0% 9.7% 2.1%

A rank error is therefore distribution-free, and that is not a virtue. It means the number would have been the same for data with any spacing whatever, which is another way of saying it carries no information about the values — and the value error, on the same summary and the same ranks, moved by a factor of ten.

Both halves are asserted on every build, including the second, because a check that only required the rank errors to match would be passed by an implementation that had stopped answering.

A rank promise of ±2% at q = 0.99 on Pareto, α = 1.2 — a heavy tailThe curve is the empirical distribution of 20,000 values: the horizontal axis is the value, logarithmic and the vertical axis is the fraction of the stream at or below it. A promise about the RANK is the shaded horizontal band, whose height is fixed at ±2% wherever it is drawn. What it permits in the ANSWER is the vertical band it cuts from the curve, and that runs from 18.5 to 4,190 — a range of 9431% of the true value at this quantile. The summary answered 52.2 against a true 44.2: a rank error of 0.13%, inside the promise, and a value error of 17.9%, about which the promise says nothing. The two errors are the same number exactly when the distribution is flat, and the gap between them is the slope of this curve.answered 52.20%25%50%75%100%11.794,190value, logarithmicfraction of the stream at or belowrank ±2%value 18.5–4,190answered 17.9% out20,000 values · Pareto, α = 1.2 — a heavy tail · Greenwald–Khanna, ε = 0.02rank 0.13% · value 17.9%
Fig. 8 The mechanism that produces the gap, from the essay that first measured it: the two errors on the same answer, with the quantile function drawn between them. A rank error is a horizontal distance and a value error is a vertical one, and the slope that converts between them is the density — which goes to zero in a tail.

Which promise a question wants

It is worth being concrete about when each rule is the right one, because “relative error” is not automatically better and the plates above can be read as though it were.

A uniform cap is right when the quantiles are being used to describe a distribution: a box plot, a histogram’s breakpoints, a median and an interquartile range. Every part of the range matters roughly equally, resolution in the tail is worth no more than resolution in the middle, and the uniform rule delivers the most resolution per bit under exactly that valuation.

A biased cap is right when the question is about an extreme: a latency percentile in a service objective, a threshold above which an alert fires, the size of the largest orders. There, the middle of the distribution is not being asked about at all, and spending an equal share of the state on it is spending most of the state on nothing.

The distinction is not about the data and it is not about which structure is better implemented. It is about what the number is going to be used for, and it is the only thing that decides which of the two error bars is the honest one to print. A summary chosen without that decision having been made will be a uniform one, because that is the default in every library — and it will be asked for tail percentiles, because that is what quantile summaries are mostly deployed for.

Those two facts are in tension and nothing reports it. A structure meeting its stated guarantee, queried at the quantile it is usually queried at, returning a number that is wrong by a factor of thirty-eight, is what that tension produces.

A third rung: resolution only where it is asked for

The essay presents two caps and there is a third, and it is the one a monitoring system actually wants — which makes its absence from the usual comparison worth noticing.

A biased summary promises relative accuracy at every quantile in the tail, and that is more than most callers need. A dashboard asks for a fixed set — the median, the 90th, the 99th, sometimes the 99.9th — and nothing else, ever. Resolution at q=0.9993q = 0.9993 is being paid for and never used.

The same invariant supports the narrower requirement. Give each target quantile its own tolerance and let the cap at rank rr be the smallest requirement any target imposes there:

f(r,n)=minqT(what target q needs at r)f(r, n) = \min_{q \in T} \bigl(\text{what target } q \text{ needs at } r\bigr)

The cap is then small near each target and large everywhere between them, so the summary is dense at four places and sparse in the gaps. Its state is governed by the number of targets rather than by a logarithm of the stream, and on a set of four it is a fraction of what the fully biased summary costs.

Which reverses the essay’s cost argument for the case it is usually applied to. The eightfold price of relative accuracy is the price of relative accuracy everywhere; the price of relative accuracy at four stated quantiles is much less, and four stated quantiles is what the query pattern is.

The catch is that the target set has to be known when the summary is built, and a dashboard that later adds a percentile is asking a question the structure was not built to answer — it will still answer, at whatever resolution the cap happened to leave there, with no indication that this query is not one of the four. That is a real hazard and it is the same one every structure in this field has: the promise is fixed at construction and the query arrives later, and nothing in the answer says which of the two it was designed for.

The failure announces itself, and nothing listens

The most striking row in this essay is the one where the answer is exactly the maximum, and it comes with a free diagnostic that no implementation reports.

If the value returned for a quantile equals the largest value the summary has seen, then the query landed in the tuple at the very top — the one whose rank interval runs to nn — and that tuple is the summary saying it has no resolution up there. The answer is not merely inaccurate; it is the structure’s way of saying no resolution up here.

Detecting it costs a comparison. Every summary in this family stores the maximum exactly, because the largest value is always a tuple boundary, so the check is: does the answer equal the stored maximum, and was qq less than one? If both, the query is past the structure’s resolution and the number should be reported as a lower bound rather than as an estimate.

Nothing does this, and the reason is the shape of the interface rather than any difficulty: a summary that returns one number has nowhere to put the caveat, and a caller that receives one number has nothing to branch on.

It is the same repair this collection keeps arriving at from different structures — report the bracket rather than the point — in the cheapest form it takes anywhere. Here it is not even a bracket: it is one boolean, computable from state the structure already holds, that separates the answer is 9,693.8 from the answer is at least 9,693.8 and this summary cannot say more.

What is not measured here

Merging. Biased summaries merge, and the merge is where quantile summaries are usually deployed — one per shard, combined at query time. The merged structure’s guarantee is weaker than either input’s and this collection has not measured by how much.

The deterministic space bound. The tuple counts above are measurements of one implementation on particular streams. The published bound for the biased variant is O(1εlog2εn)O(\frac{1}{\varepsilon}\log^2 \varepsilon n) against Greenwald–Khanna’s O(1εlogεn)O(\frac{1}{\varepsilon}\log \varepsilon n), and one extra logarithm is consistent with the eightfold gap seen here without being demonstrated by it.

And the compression pass here is the greedy one. Greenwald–Khanna’s banded variant reaches a better space bound while maintaining the same invariant and therefore the same guarantee. Both structures above use the plain greedy pass, so the comparison between them is fair and the absolute tuple counts are larger than the best known.

Rank error as a fraction of the tail it is aboutThe same measurements as a plate reporting error against the stream, divided by the mass the quantile is about — 1 − q, which is a half at the median and a thousandth at q = 0.999. Averaged over 8 independent streams of 40,000 lognormal values. A relative promise is a flat line on this plate and an absolute one climbs, because the numerator is constant and the denominator is shrinking. Greenwald–Khanna: 1.12% → 1.81% → 1.91% → 39% → 100%; high-biased: 0.43% → 0.54% → 0.36% → 0.44% → 0.00%; t-digest: 0.26% → 0.28% → 0.82% → 5.72% → 29%. The vertical axis is logarithmic.0.1%1%10%100%0.50.750.90.990.999quantile asked forrank error ÷ (1 − q)Greenwald–Khanna7,128 bitshigh-biased55,560 bitst-digest5,952 bits8 streams per point · ε = 0.01, δ = 100denominator: the tail
Fig. 9 The same plate on a log-normal stream, which is what a latency distribution actually looks like. The shape is the same because the shape is a property of the invariant rather than of the data — which the next section but one makes exact.

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.

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.

Greenwald–KhannaGuaranteeHeavy tailHonest limitMeasurementQuantileRank errorState bitsSummaryTailTail latencyTrade off