When the algorithm flips a coin

A penalty set by the block

A blocked Bloom filter pays a penalty for its uneven block loads, and a threshold that lets a lookup work out its block repays about a third of it — measured on 2,048 keys, with a prediction that larger filters would widen the gain. From 2,048 keys to 131,072 nothing moves: one block holds 0.085% to 0.090% against a computed 0.086%, and the threshold design 0.063% to 0.066%. The busiest block grows and the rate does not follow it. What sets both the penalty and the repair is the keys a block holds. A threshold turns out to be worth one doubling of the block's width, and nothing once a block holds 128 keys.

A block the lookup can work out measured a repair for the penalty a blocked Bloom filter pays. Confining a key’s bit positions to one 512-bit block makes a lookup read one cache line, and costs false positives, because some blocks draw more keys than others and a Bloom filter’s error is convex in its load. Giving each key a second candidate block and each block a threshold on a hash of the key lets a lookup work out which block a key went to. That flattens the load and keeps a single block read. At sixteen bits a key on 2,048 keys it measured 0.0628% against one block’s 0.0954%, recovering about two thirds of what an oracle lookup could.

Its list of things not settled ended with the size of the filter. Everything had been measured at 2,048 keys, and the page argued that on a larger filter the advantage over one block should widen: the number of blocks grows with the keys, so the tail of the load distribution grows, and with it the penalty the threshold exists to repair. It said plainly that this was an argument and not a measurement.

This page measures it. The argument fails, the reason it fails is worth having, and the variable that actually decides the penalty turns out to be one the earlier pages held fixed.

The rate does not see the filter’s size

The measurement is the earlier page’s three designs, built exactly as it built them, at sixteen bits a key and 512-bit blocks, on filters of 2,048, 8,192, 32,768 and 131,072 keys: a 64-fold range. Every point is two million lookups of absent keys, spread over as many filters as keep the measurement affordable. That is enough to resolve a rate near 0.06% to a few per cent. Beside the one-block rate is a computed one: Bloom’s formula applied inside a block, averaged over the block’s load, with the load drawn from a Poisson distribution whose mean is the keys a block holds, 32 here.

From 2,048 keys to 131,072 the rates do not move: one block 0.085% to 0.090% against a Poisson average of 0.086%, the threshold design 0.063% to 0.066%The false-positive rate at sixteen bits a key and 512-bit blocks, against the keys a filter holds, two million absent queries a point. 2,048 keys: one block 0.0897%, the emptier of two 0.0985%, the threshold design 0.0663%; 8,192 keys: one block 0.0905%, the emptier of two 0.1015%, the threshold design 0.0628%; 32,768 keys: one block 0.0849%, the emptier of two 0.1003%, the threshold design 0.0643%; 131,072 keys: one block 0.0876%, the emptier of two 0.0971%, the threshold design 0.0660%. The dashed line is the one-block rate averaged over a Poisson load, 0.0860%, the same at every size. Both axes are logarithmic.10,000100,000keys in the filtershare of absent keys answered yes0.04%0.05%0.06%0.08%0.10%0.12%the emptier of twoone blockone block, Poisson averageone block, by threshold16 bits a key, 512-bit blocks2,000,000 absent queries a point
Fig. 1 The false-positive rate at sixteen bits a key and 512-bit blocks against the keys in the filter, both axes logarithmic. One block: 0.0897%, 0.0905%, 0.0849% and 0.0876% at 2,048, 8,192, 32,768 and 131,072 keys, against the computed Poisson average of 0.0860% (dashed) at every size. The emptier of two: 0.0985% to 0.1015%. The threshold design: 0.0663%, 0.0628%, 0.0643% and 0.0660%.

Nothing moves. One block’s rate wanders between 0.085% and 0.091% across a 64-fold range of sizes, around a computed value of 0.086% that does not depend on the size at all. The threshold design stays between 0.063% and 0.066%, 24% to 31% under one block at every size. The emptier-of-two design stays near 0.1%, its doubled chance of a false positive intact. Two blocks and the chances they add measured that doubling at 2,048 keys, and it is exactly as large at 131,072: a lookup that must ask two blocks is wrong twice as often however many blocks there are to ask, because the chance is set per lookup, not per filter. The advantage the earlier page predicted would widen is the same at 131,072 keys as at 2,048.

The computed line explains why. A lookup for an absent key lands in a block chosen by a hash, so every block is equally likely to be asked, and the filter’s rate is the mean of its blocks’ rates. Each block’s rate depends only on how many keys it holds. In a one-choice filter every block’s load has the same distribution — binomial, with a mean of the block’s width divided by the bits a key — whatever the number of blocks. More blocks means more samples from that distribution, not a different distribution, and a mean over more samples of the same thing is the same mean.

The tail grows and the rate does not follow it

The earlier page’s argument was not wrong about the tail. It was wrong about what the rate is.

The busiest block does grow with the filter — 51 keys to 57 under one choice — and the rate does not follow it, because the busiest block is one of 4,096The most keys any block held, over every filter built at a point, against the keys in the filter, at sixteen bits a key and 512-bit blocks, whose mean load is 32 keys. One block: 51, 50, 55, 57. One block, by threshold: 42, 40, 42, 43. The emptier of two: 35, 35, 35, 35. The dashed line is the mean load. Both axes are logarithmic.10,000100,000keys in the filterkeys in the busiest block30354045505560mean load, 32 keysone blockone block, by thresholdthe emptier of two16 bits a key, 512-bit blocksthe busiest block of all built
Fig. 2 The most keys any block held, over every filter built at a point, against the keys in the filter, both axes logarithmic; the mean load is 32 keys (dashed). One block: 51, 50, 55 and 57 keys. The threshold design: 42, 40, 42 and 43. The emptier of two: 35 at every size.

The busiest block does grow with the filter. Under one choice it holds 51 keys at 2,048 and 57 at 131,072 — the maximum of more draws from the same distribution, rising slowly, the way the second choice measured a hash table’s worst bucket rising. The threshold design’s busiest block grows less, from 42 to 43, and the emptier of two holds its busiest block at exactly 35 at every size. All three shapes are the balls-in-bins results already measured for hash tables.

But a false-positive rate is not a maximum. The busiest block at 131,072 keys is one block of 4,096, and a lookup reaches it once in 4,096 tries. Its rate is higher than the average, and it gets its share of the average, a share that falls exactly as fast as the tail rises. A worst case that grows with the number of blocks moves a quantity that averages over blocks by nothing. The earlier argument carried a statement about the maximum across to a quantity that is a mean. That is the same slip distributions, not averages keeps warning about, taken in the other direction: here the average is the question and the tail is the distraction.

The threshold design shows the same thing in a second way. Its advantage over one block comes from narrowing the whole load distribution, not from trimming the maximum. Its load spread is 3.4 keys against one block’s 5.6 at every size, and the spread of a distribution does not depend on how many samples are drawn from it.

Which quantities a filter’s size can move

The distinction is worth making general, because it decides in advance whether a measurement at one size says anything about another.

A quantity that is an average over lookups — a false-positive rate, an expected number of lines read, an expected number of probes — is a property of the distribution a single lookup meets. A lookup meets one block, chosen by a hash, and the load of that block has the same distribution in a filter of a thousand blocks as in a filter of a million. Every quantity of that kind is the same at every size, however it is computed. The same holds for a quantile over lookups: the 99.9th percentile of the load a lookup meets is a quantile of the same distribution, and it does not grow either.

A quantity that is a statement about every block is different. The fullest block, the chance that some block overflows, the capacity a design must reserve so that no block ever refuses a key — these are statements about a maximum, and the maximum of more samples grows. The second choice measured exactly that growth for a hash table’s worst bucket, and it is where the earlier page’s intuition came from. It applies wherever a structure fails at its fullest block. A bucketed table with a fixed number of slots a bucket is one: its capacity has to cover the busiest bucket or an insertion fails, and an insertion that can fail is what that failure looks like from the caller’s side. A Bloom filter never refuses a key, so it has no such quantity. Its busiest block simply answers yes a little more often, to the one lookup in thousands that reaches it.

So the question to ask of any blocked structure, before measuring it at a larger size, is which of the two kinds of quantity is being claimed. The bucket that fits a line sized its buckets to a cache line and had to find room for every key, which is a claim about the fullest bucket; a filter confined to a line only has to average well. The two designs share a shape and answer to different statistics.

What the width decides

If the size does not decide the penalty, something else must, and the computed line says what: the mean load of a block, which is its width in bits divided by the bits a key. The earlier pages held it at 32 by fixing 512-bit blocks at sixteen bits a key. Sweeping the width moves it.

Widen the block and one block's penalty falls towards an unblocked filter's 0.046%; the threshold's advantage falls with it, from 39% at 256 bits to nothing at 2,048The false-positive rate at sixteen bits a key on 8,192 keys, against the width of a block in bits. 256 bits (16 keys a block): one block 0.1424% against a Poisson average of 0.1362%, the emptier of two 0.1135%, the threshold design 0.0871%, 39% under one block; 512 bits (32 keys a block): one block 0.0905% against a Poisson average of 0.0860%, the emptier of two 0.1015%, the threshold design 0.0628%, 31% under one block; 1,024 bits (64 keys a block): one block 0.0634% against a Poisson average of 0.0646%, the emptier of two 0.0940%, the threshold design 0.0554%, 13% under one block; 2,048 bits (128 keys a block): one block 0.0524% against a Poisson average of 0.0549%, the emptier of two 0.0945%, the threshold design 0.0552%, 5% over one block; 4,096 bits (256 keys a block): one block 0.0500% against a Poisson average of 0.0503%, the emptier of two 0.0935%, the threshold design 0.0594%, 19% over one block. The dotted line is a filter of the same bits with no blocks. Both axes are logarithmic.1,000bits in a blockshare of absent keys answered yes0.04%0.05%0.06%0.08%0.10%0.12%0.15%an unblocked filter, 0.046%the emptier of twoone blockone block, Poisson averageone block, by threshold16 bits a key, 8,192 keysdotted: no blocks at all
Fig. 3 The false-positive rate at sixteen bits a key on 8,192 keys against the width of a block, both axes logarithmic. One block: 0.1424%, 0.0905%, 0.0634%, 0.0524% and 0.0500% at 256, 512, 1,024, 2,048 and 4,096 bits, against computed values of 0.1362%, 0.0860%, 0.0646%, 0.0549% and 0.0503%. The threshold design: 0.0871%, 0.0628%, 0.0554%, 0.0552%, 0.0594%. The emptier of two: 0.094% to 0.114%. The dotted line is the same bits with no blocks, 0.0459%.

One block’s penalty falls steadily as the block widens, from 3.1 times an unblocked filter’s rate at 256 bits to 1.1 times at 4,096. The reason is the Poisson spread. A block holding λ\lambda keys on average has a spread of λ\sqrt{\lambda}, so the spread as a share of the load is 1/λ1/\sqrt{\lambda}: a quarter at 16 keys, an eighth at 64, a sixteenth at 256. A narrower relative spread means the convexity of Bloom’s formula has less to act on. The computed line follows the measurement at every width to within 6%, which is the resolution the queries allow.

The threshold’s advantage falls with it. It is 39% under one block at 256 bits, 31% at 512, 13% at 1,024, and gone at 2,048. The threshold repairs the spread, and there is less spread to repair when blocks are wide. At the widest two widths on this plate it is behind one block — 5% at 2,048 bits and 19% at 4,096 — and that part is not the width at all.

It is the price of the thresholds, paid in the currency the earlier page chose. To keep every block aligned to a cache line, the thresholds are paid for by dropping whole blocks, not by narrowing every block. At 4,096-bit blocks on 8,192 keys there are only 32 blocks, and a table of 32 eight-bit thresholds costs one of them, 3% of the filter’s capacity for 256 bits of table. On 131,072 keys there are 512 blocks and the table costs one block in 512. Measured there, the threshold design is 8% under one block at 2,048 bits (0.0505% against 0.0550%) and level at 4,096 (0.0495% against 0.0490%). So the filter’s size does enter, once, through the rounding of the table into whole blocks — and there it matters least exactly where the earlier page expected it to matter most.

A threshold is worth a doubling

The width sweep says what a threshold buys. The question a designer asks is what it costs, and the cost of a blocked filter is the lines a lookup reads.

A threshold is worth a doubling of the block: at 512 bits it measures 0.0628% reading two lines, one of them a table that stays in cache; one block of 1,024 bits measures 0.0634% reading two lines of the filterThe false-positive rate against the distinct 512-bit lines a lookup for an absent key reads, for one block and for one block chosen by a threshold, at block widths of 256, 512, 1,024, 2,048, 4,096 bits, sixteen bits a key, 8,192 keys. One block at 256 bits: 1.00 lines, 0.1424%; One block at 512 bits: 1.00 lines, 0.0905%; One block at 1,024 bits: 2.00 lines, 0.0634%; One block at 2,048 bits: 3.83 lines, 0.0524%; One block at 4,096 bits: 6.16 lines, 0.0500%; One block, by threshold at 256 bits: 2.00 lines, 0.0871%; One block, by threshold at 512 bits: 2.00 lines, 0.0628%; One block, by threshold at 1,024 bits: 3.00 lines, 0.0554%; One block, by threshold at 2,048 bits: 4.83 lines, 0.0552%; One block, by threshold at 4,096 bits: 7.16 lines, 0.0594%. The threshold design's line count includes the line holding the thresholds. Both axes are logarithmic.1248distinct lines a lookup reads, the threshold table includedshare of absent keys answered yes0.05%0.06%0.08%0.10%0.12%0.15%256 bits512 bits1,024 bits256 bits512 bitsone blockone block, by thresholdwidths rise from 256 bits to4,096 along each line16 bits a key, 8,192 keyslines of 512 bits
Fig. 4 The false-positive rate against the distinct 512-bit lines a lookup for an absent key reads, both axes logarithmic, sixteen bits a key on 8,192 keys; the digits are block widths in bits. One block: 1.00 line at 256 and 512 bits, 2.00 at 1,024, 3.83 at 2,048, 6.16 at 4,096. By threshold, the threshold line included: 2.00, 2.00, 3.00, 4.83, 7.16. A threshold on a 512-bit block measures 0.0628% at two lines; one block of 1,024 bits, 0.0634% at two lines.

A threshold on a block of ww bits gives about the rate of one block of 2w2w bits, at the line count of the narrower block plus one. At 256 bits the threshold design measures 0.0871% against one 512-bit block’s 0.0905%. At 512 it measures 0.0628% against one 1,024-bit block’s 0.0634%. At 1,024 it measures 0.0554% against 2,048’s 0.0524%, and the rule starts to slip as the penalty runs out.

The equivalence on line counts is exact at the width that matters most. A threshold on a 512-bit block reads two lines, and so does one block of 1,024 bits: a 1,024-bit block spans two lines and a lookup’s eleven bit positions almost always touch both. The two designs have the same rate and the same line count, and the lines are different objects. The 1,024-bit block’s two lines are both random lines of a large filter. The threshold design’s second line is the table of thresholds, a few dozen bytes read by every lookup, which on any real machine would sit permanently in the first-level cache. One access, eight kilobytes is the page on why a line that is always hot is not the same cost as a line that is not.

The plate also shows the ceiling on the whole idea. Positions confined to one line confined a key to one line to make a lookup cost one line, and every repair since has spent a little of that back. A threshold spends a line that is nearly free to buy a doubling of the width. Beyond that, a wider block is simply a less blocked filter, and at 4,096 bits the design is reading six lines for a rate 9% above the unblocked filter’s — whose lookup reads eleven. The design space between one line and no blocking at all is one doubling wide, and a threshold covers it.

Where the repair goes as the block widens

As blocks widen the threshold design sends fewer keys to a second block — 11% at 256 bits, 3% at 4,096 — and flattens the load by the same share throughout, about 0.59 of one block's spreadFor the threshold design at sixteen bits a key on 8,192 keys, against block width: the share of keys placed in their second block, the standard deviation of block loads as a share of one block's, and the share of the budget the thresholds take. Keys sent to their second block: 10.7%, 7.5%, 5.7%, 4.6%, 3.2%. Load spread, threshold ÷ one block: 63.2%, 58.5%, 57.4%, 58.7%, 54.4%. Budget spent on thresholds: 3.0%, 1.5%, 0.8%, 0.4%, 0.2%. Both axes are logarithmic.2565121,0242,0484,096bits in a blockshare0.2%0.5%1%2%5%10%20%50%keys sent to their second blockload spread, threshold ÷ oneblockbudget spent on thresholds16 bits a key, 8,192 keysthe threshold design
Fig. 5 For the threshold design at sixteen bits a key on 8,192 keys, against block width, both axes logarithmic: the share of keys sent to their second block, 10.7%, 7.5%, 5.7%, 4.6% and 3.2% from 256 bits to 4,096; its load spread as a share of one block’s, 63%, 59%, 57%, 59% and 54%; and the share of the budget the thresholds take, 3.0% down to 0.2%.

The threshold design flattens the load by a nearly constant share at every width: its spread is 54% to 63% of one block’s. What changes is what that flattening is worth. At 256 bits a block’s spread is a quarter of its load, and removing four tenths of it removes most of the penalty. At 4,096 bits the spread is a sixteenth, and removing four tenths of it removes four tenths of almost nothing. The overflow into second blocks falls as blocks widen too, because a wide block rarely reaches its capacity. The keys it does send are still the 3 to 11% that land in blocks with no say, which a block the lookup can work out identified as the whole of the remaining spread.

So the earlier page’s question has its answer in a different variable. It asked whether the threshold would be worth more on a larger filter. The answer is no, because the size does not change the load distribution. It is worth more on a narrower block, because the width does. A designer who wants the threshold’s benefit should look at the keys a block holds: 16 to 64 is where it pays, and 128 or more is where it has nothing left to do.

What was measured and what was not

Sixteen bits a key throughout. The mean load is width divided by bits a key, so a denser filter is equivalent to a wider block. At eight bits a key a 512-bit block holds 64 keys, and the earlier page’s finding that the threshold loses at eight bits a key is this page’s 1,024-bit column seen from the other side.

The computed line assumes a Poisson load. A one-choice filter’s load is binomial, and the Poisson distribution is its limit when blocks are many. At 16 blocks the two differ in the tail, which is why the plates build filters of at least 2,048 keys. Every measured one-block point is within 6% of the computed one, and that agreement is the evidence that nothing except the load distribution is at work.

The threshold design’s table is paid in whole blocks. That choice belongs to the earlier page and keeps every block on a line. On small filters with wide blocks it costs more than the table’s bits, and the 5% and 19% losses at 2,048 and 4,096 bits on 8,192 keys are that rounding, not the design. The 131,072-key measurements, 8% ahead and level, are the design.

Random keys. Every filter here holds keys drawn from a seeded random source, and every lookup is for a key drawn the same way. The adversary who knows the seed is the page on what happens when the keys are chosen, and a blocked filter’s weakest point is the block an adversary can fill.

Still open: a threshold on both blocks

Everything the threshold design leaves on the table is the overflow. A block that fills stops accepting keys for which it is the first choice. It cannot refuse keys for which it is the second, so the 3 to 11% of keys that overflow land wherever their second hash sends them, and a block can be pushed past its design load by keys it never agreed to take. On every width here the design’s load spread stays at more than half of one block’s, and the overflow is why.

The obvious repair has a cost the earlier page named: a key refused by both of its blocks needs somewhere to go. The measurement that follows gives each key a third candidate and every block a threshold on both first- and second-choice keys, sends a doubly refused key to the third, and has the lookup read two thresholds before it reads a block. It asks how much of the remaining spread that removes, what the second threshold line costs, and whether the design then reaches the rate of a block four times its width rather than two. The prediction is that it removes most of the remaining spread at 512 bits, and that it is not worth doing at 1,024 or wider, because by then the penalty it would repair is 13% and the second threshold costs another line.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

The objects this essay names

Each one links to every other essay that touches it.

Balls in binsBlocked filterBloom filterCacheDesign parameterFalse-positive rateLoad balancingLocalityMaximum loadPoissonThresholdTwo choices