When it does not fit

One length for the gaps and the clusters

On uniform keys one prefix length a level, chosen for its memory, beat a filter holding every length from 12 to 24 bits. Clustering the keys was predicted to reverse that, because coarse prefixes between clusters are empty and a coarse filter can then say no to a long range in one question. Clustering alone does not: whether ranges fall in the gaps or at the keys, one length re-chosen for that workload still wins, since it moves coarse for the gaps and fine for the keys. The multi-resolution filter wins only where a clustered store is asked both — by 0.17 transfers a query at ten bits a key on sixteen clusters — and it wins on short ranges inside the clusters, not on long ones between them.

The resolution a range filter can afford set two designs against each other on a four-level log-structured store of 2202^{20} keys. The first keeps one Bloom filter a level over the keys’ prefixes at a single length, chosen for the level and the memory. The second keeps prefix filters at every length from 16 to 24 bits in the same memory and asks a range from the coarsest length down, refining only below the answers that come back yes. Chosen again for each memory, one length a level won at every memory from two bits a key to thirty-two. The reason was a plate of occupancies. On uniform keys the largest level holds a key in every 16-bit prefix and in 93% of 18-bit ones. A coarse question there is truthfully answered yes and rules out nothing, and the memory spent on coarse filters buys no skip.

Its closing section said the uniform keys were the reason and proposed clustered ones. Timestamps arrive in bursts and identifiers are handed out in blocks, so a key space of 32 bits holding a million keys in a few dense regions has most of its coarse prefixes empty. The prediction was that the coarse filters would then say no to long ranges between the clusters, and that the multi-resolution filter would pay on clustered keys and not on uniform ones. It named the way it could fail. Clustering might make the fine prefixes inside a cluster denser, so that the best single length moved finer inside the clusters and coarser between them, and one level would want two lengths at once.

The store, the clusters and the questions

The store is the earlier pages’ in everything but where its keys come from: four levels of 16K, 64K, 256K and 688K keys, charged one transfer to find a range’s start in a level and one more for every 64 keys it reads there. A level is skipped only when its filter can show that no prefix the range touches holds a key, and every skip is checked against the level’s keys. Here the keys are drawn from a stated number of windows of key space, each placed at random and filled uniformly, the windows together covering a sixteenth of the space. Five stores are measured: uniform keys, and keys in 65,536, 4,096, 256 and 16 clusters. The multi-resolution filter now keeps eleven lengths, 12 and 14 bits and every length from 16 to 24, since on a clustered store a 12-bit prefix can be empty, and as before each stored prefix gets the same share of the level’s memory.

A range is the same width as before, wide enough to hold a tenth of a key, one, ten or a hundred keys on the uniform store. On a clustered store the width matters more than the count, because a range of that width holds sixteen times as many keys inside a cluster and none in a gap. So where ranges start is now part of the question. Three workloads are measured: ranges that start anywhere in key space, most of which on a clustered store fall in the gaps; ranges centred on a stored key, which fall inside the clusters; and half of each.

Most coarse prefixes are empty

Where a coarse filter can say no: on the largest level, uniform keys occupy 100% of 16-bit prefixes, keys in 4,096 clusters 11.72% and keys in 16 clusters 6.08%; at 12 bits the sixteen clusters leave 94% of prefixes empty, and every clustering converges on the uniform store's share by 24 bitsThe largest level of the store, 704,512 keys, with keys drawn uniformly or from windows of key space together covering one sixteenth of it. For each prefix length from 12 to 24 bits, the share of prefixes of that length holding at least one key. Uniform: 12 bits 100.0%, 14 bits 100.0%, 16 bits 100.0%, 17 bits 99.5%, 18 bits 93.2%, 19 bits 73.9%, 20 bits 49.0%, 21 bits 28.6%, 22 bits 15.5%, 23 bits 8.1%, 24 bits 4.1%. 65,536 clusters: 12 bits 100.0%, 14 bits 98.1%, 16 bits 65.2%, 17 bits 42.4%, 18 bits 26.0%, 19 bits 16.2%, 20 bits 10.8%, 21 bits 7.9%, 22 bits 6.2%, 23 bits 4.6%, 24 bits 3.0%. 4,096 clusters: 12 bits 66.4%, 14 bits 26.8%, 16 bits 11.7%, 17 bits 8.9%, 18 bits 7.5%, 19 bits 6.7%, 20 bits 6.4%, 21 bits 6.2%, 22 bits 5.7%, 23 bits 4.5%, 24 bits 3.0%. 256 clusters: 12 bits 11.7%, 14 bits 7.5%, 16 bits 6.4%, 17 bits 6.2%, 18 bits 6.1%, 19 bits 6.1%, 20 bits 6.1%, 21 bits 6.0%, 22 bits 5.7%, 23 bits 4.5%, 24 bits 3.0%. 16 clusters: 12 bits 6.4%, 14 bits 6.1%, 16 bits 6.1%, 17 bits 6.1%, 18 bits 6.1%, 19 bits 6.1%, 20 bits 6.1%, 21 bits 6.0%, 22 bits 5.7%, 23 bits 4.6%, 24 bits 3.1%.025507510012141618202224prefix length, bitsper cent of prefixes holding a keyuniform65,536 clusters4,096 clusters256 clusters16 clusterslargest level, 704,512 keysclusters cover a sixteenth of key space
Fig. 1 The share of prefixes holding a key on the largest level, by prefix length. Uniform keys: 100% at 12 and 16 bits, 49% at 20, 4.1% at 24. In 4,096 clusters: 66%, 12%, 6.4%, 3.0%. In 16 clusters: 6.4%, 6.1%, 6.1%, 3.1%.

On the largest level, keys in sixteen clusters leave 94% of 12-bit prefixes empty and 94% of 16-bit ones, where uniform keys fill all of them. The clusters cover a sixteenth of key space, so at any length coarse enough for a cluster to span many prefixes the occupied share settles at about 6%. Only at the finest lengths, where the prefixes are narrower than the gaps between keys inside a cluster, does the share start to fall again, and by 24 bits every store is near the uniform one’s 4%. The premise of the prediction holds as stated: on clustered keys a coarse filter has something to say no to. A penalty set by the block put a filter’s whole value in the questions it can answer no, and on the uniform store the coarse filters had none.

There is a second consequence the prediction did not name, and it matters as much. A multi-resolution filter divides its memory among its lengths by distinct prefixes, and on a clustered store the coarse and middle lengths have few. On the largest level at ten bits a key, uniform keys give the filter about four million distinct prefixes across its eleven lengths, and the 24-bit filter gets 17% of the memory — 1.8 bits for each prefix it stores. Sixteen clusters give it 1.4 million distinct prefixes. The 24-bit filter gets 37% of the memory and every stored prefix 5.1 bits. A floor on the bits set the least a membership structure can spend at the logarithm of one over its false-positive rate, and 1.8 bits a prefix is below any useful rate. On clustered keys the same division leaves each filter nearly three times the bits, and the coarse ones cost almost nothing to keep: lengths 12 to 18 together hold 2% of the memory.

Clustering alone changes nothing

Which design wins, at 10 bits a key: the multi-resolution filter's transfers a range query minus those of one length a level chosen for the same store, workload and memory — positive everywhere a workload asks only in the gaps or only at the keys, and negative only where a clustered store is asked both, by 0.172 transfers on 16 clusters (3 of 15 cells)Rows: three workloads — ranges starting uniformly over key space, ranges centred on a stored key, and half of each. Columns: the store's keys uniform or in 65,536, 4,096, 256, 16 clusters covering a sixteenth of key space. Each cell: the multi-resolution filter's mean transfers a range query minus one length a level's, both at 10 bits a key; negative means the multi-resolution filter is cheaper. Ranges anywhere in key space: uniform +0.186 (4.103 against 3.917), 65,536 clusters +0.094 (3.030 against 2.935), 4,096 clusters +0.065 (1.420 against 1.354), 256 clusters +0.028 (0.950 against 0.923), 16 clusters +0.019 (0.817 against 0.797). Ranges at stored keys: uniform +0.161 (4.836 against 4.675), 65,536 clusters +0.068 (6.043 against 5.975), 4,096 clusters +0.076 (7.658 against 7.582), 256 clusters +0.078 (12.375 against 12.296), 16 clusters +0.064 (12.585 against 12.522). Half of each: uniform +0.172 (4.477 against 4.305), 65,536 clusters +0.046 (4.558 against 4.512), 4,096 clusters −0.109 (4.504 against 4.613), 256 clusters −0.165 (6.671 against 6.836), 16 clusters −0.172 (6.697 against 6.869).uniform65,536 clusters4,096 clusters256 clusters16 clustersranges anywhere in key space+0.186+0.094+0.065+0.028+0.019ranges at stored keys+0.161+0.068+0.076+0.078+0.064half of each+0.172+0.046−0.109−0.165−0.172filled: the multi-resolution filter is cheapertransfers a range query, 10 bits a key
Fig. 2 The multi-resolution filter’s transfers a range query minus one length a level’s, at ten bits a key, both chosen for the same store and workload. Ranges anywhere: +0.186 on uniform keys down to +0.019 on 16 clusters. Ranges at keys: +0.161 down to +0.064. Half of each: +0.172 on uniform keys, +0.046 on 65,536 clusters, then −0.109, −0.165 and −0.172 on 4,096, 256 and 16.

Asked only in the gaps or only at the keys, one length a level beats the multi-resolution filter on every store, clustered or not. At ten bits a key and ranges starting anywhere, the margin falls from 0.186 transfers a query on uniform keys to 0.019 on sixteen clusters, and it never changes sign. At ranges centred on keys it falls from 0.161 to 0.064. The prediction said the multi-resolution filter would pay on clustered keys. On any workload that asks one kind of question it does not, and the reason is on the next plate.

Asked both, on a clustered store, the multi-resolution filter wins: by 0.109 transfers a query on 4,096 clusters, 0.165 on 256 and 0.172 on 16. It loses on uniform keys, by 0.172, and on 65,536 clusters, where the clusters are small enough to fill most prefixes down to 16 bits, by 0.046. Three cells of fifteen are negative, and they are the three where the store has large empty regions and the workload puts ranges both inside and between them. The choice between the two designs is a property of the keys and the questions together. Neither is enough on its own, and that is the failure the section named: one level wanting two lengths at once.

What a single length does when it is chosen

No one length fits both kinds of range, on 16 clusters at 10 bits a key: chosen for ranges anywhere in key space the four levels take 18, 19, 21, 16 bits; chosen for ranges at stored keys, 23, 25, 26, 26; chosen for half of each, 20, 20, 21, 16 — a compromise that is the right length for neitherFor the store with keys in 16 clusters covering a sixteenth of key space and 10 bits a key of filter memory, the prefix length that minimises each level's transfers, chosen separately for three workloads. Ranges anywhere in key space: 16K keys 18 bits, 64K keys 19 bits, 256K keys 21 bits, 688K keys 16 bits. Ranges at stored keys: 16K keys 23 bits, 64K keys 25 bits, 256K keys 26 bits, 688K keys 26 bits. Half of each: 16K keys 20 bits, 64K keys 20 bits, 256K keys 21 bits, 688K keys 16 bits.1216202428prefix length, bitsranges anywhere in key spaceranges at stored keyshalf of eachdots, smallest level to largest: dark to light16 clusters, 10 bits a key
Fig. 3 The best prefix length for each level on sixteen clusters at ten bits a key. For ranges anywhere in key space: 18, 19, 21 and 16 bits, smallest level to largest. For ranges at stored keys: 23, 25, 26, 26. For half of each: 20, 20, 21, 16.

One length a level, chosen again for the workload, already does what the prediction expected only the coarse filters could do. For ranges that start anywhere, on sixteen clusters, the largest level’s best length is 16 bits; for ranges at the keys it is 26. A 16-bit prefix is 65,536 values of key space wide, so a range of a hundred keys’ width falls in seven or eight of them, and in a gap the filter answers every one of them no. The coarse length does the gaps’ work at one resolution, and nothing else asks this level anything. For ranges centred on keys the gaps never come up, and the level’s length moves as fine as its memory affords, because every range now lies inside a cluster where only a fine prefix separates it from the keys around it.

The four levels pull further apart than they did on uniform keys. The uniform store’s best lengths at ten bits a key run from 19 bits on the smallest level to 24 on the largest. On sixteen clusters they run from 18 to 16 for the gaps and from 23 to 26 at the keys. A level’s best length is its best compromise between separating a range from its neighbours, which wants fine prefixes, and not asking too many questions of too sparse a filter, which wants coarse ones. The first matters inside a cluster and the second in a gap. When one kind of range dominates, the compromise is easy.

With half of each it is not. Chosen for the mix, the four levels take 20, 20, 21 and 16 bits, and on the three smaller levels that is between what either kind of range wants. The largest level keeps 16 bits. It holds two thirds of the keys, so a range at a stored key usually finds some of them there and its filter has little to skip; its length is chosen by the gaps. The smaller levels cannot make that choice. A fine length there turns a long gap range into thousands of prefixes, which exceed the probe limit of 256 and read the level. A coarse one answers every short range inside a cluster with a yes.

What the compromise gives up, range by range

What one length for a mixed workload gives up, on 16 clusters at 10 bits a key: on ranges in the gaps it costs 0.883 transfers where a length chosen for them costs 0.797, and on ranges at the keys 12.855 against 12.522; the multi-resolution filter, asking each range at the resolution it turns out to need, costs 0.817 and 12.585 — 48% and 64% of the way from the compromise to the oracleThe store with keys in 16 clusters, 10 bits a key. Each kind of range is charged on its own: ranges starting anywhere in key space, most of which fall between clusters, and ranges centred on a stored key. For each, the mean transfers a query of one length a level chosen for the half-and-half mix (20/20/21/16 bits), of the multi-resolution filter, and of one length a level chosen for that kind alone, with the oracle. Ranges anywhere in key space: one length, chosen for the mix 0.883, multi-resolution 0.817, one length, chosen for this kind 0.797; the oracle 0.746. Ranges at stored keys: one length, chosen for the mix 12.855, multi-resolution 12.585, one length, chosen for this kind 12.522; the oracle 12.432. Each group's bars are drawn on its own scale, from nine tenths of its oracle.ranges anywhere in key spaceone length, chosen for the mix0.883multi-resolution0.817one length, chosen for this kind0.797ranges at stored keysone length, chosen for the mix12.855multi-resolution12.585one length, chosen for this kind12.522dotted: the oraclebars start at nine tenths of the oracle
Fig. 4 Each kind of range charged on its own, sixteen clusters, ten bits a key. In the gaps: one length chosen for the mix 0.883 transfers a query, multi-resolution 0.817, one length chosen for gaps alone 0.797, the oracle 0.746. At the keys: 12.855, 12.585, 12.522 and 12.432.

Split by kind, the compromise length costs 0.883 transfers a query on ranges in the gaps and 12.855 on ranges at the keys; the multi-resolution filter costs 0.817 and 12.585. Each kind’s own best length costs 0.797 and 12.522. On either kind alone the multi-resolution filter is a little behind the length chosen for that kind, which is why it loses on every single workload. Against the length chosen for the mix it is ahead on both kinds. It closes 48% of the compromise’s excess over the oracle in the gaps and 64% at the keys, because it asks each range at the resolution that range turns out to need.

The saving is not where the prediction put it. It expected the coarse filters to earn their keep by skipping long ranges between clusters. They do skip them, but the single length already skipped most of them, and on ranges of a hundred keys’ width in the gaps the multi-resolution filter saves only 0.17 transfers against the compromise, 2.12 against 2.29. The large saving is on the shortest ranges inside the clusters: a range of a tenth of a key’s width at a stored key costs 3.62 transfers with the multi-resolution filter and 4.50 with the compromise length, and the share of empty levels read wrongly falls from 53% to 16%. That is the 24-bit filter doing what a 20-bit filter cannot, separating a tiny range from the keys a few thousand values away in a dense cluster.

The coarse filters are what let the fine one exist. A single length of 24 bits on the smaller levels would have served the short ranges at the keys and lost every long range in the gaps to the probe limit. In the multi-resolution filter a long gap range is answered no at 12 or 14 bits in one or two questions and never reaches the 24-bit filter’s thousands of prefixes. So the coarse filters’ contribution is mostly indirect. They take the long gap ranges off the fine filter’s hands, and the fine filter then serves the short ranges at the keys that the compromise could not. A tree with nodes the size of a block descends only into branches that could hold an answer, and the descent here does the same over prefix lengths. On clustered keys, and not before, the upper branches are empty often enough for the descent to prune. The layout that is told nothing found a structure that needed no parameter to be near the best at every block size; the descent is the filter’s version of that, near the best for both kinds of range without being told which one it is answering.

The crossing moves with the memory

On clustered keys asked both between and at them, the multi-resolution filter overtakes one length a level at 8 bits a key and stays ahead — 0.172 transfers a range query cheaper at ten bits — while on uniform keys it is behind at every memory up to twenty and ties at thirty-two, −0.001Half of the range queries start anywhere in key space and half are centred on a stored key; ranges expected to hold 0.1, 1, 10 and 100 keys on the uniform store, 600 of each. The multi-resolution filter's mean transfers a query minus those of one length a level chosen for the same store, workload and memory, against the filter memory in bits a key. Keys in 16 clusters: 2 bits +0.939, 5 bits +0.010, 8 bits −0.164, 10 bits −0.172, 16 bits −0.128, 20 bits −0.132, 32 bits −0.134. Uniform keys: 2 bits +0.749, 5 bits +0.516, 8 bits +0.270, 10 bits +0.172, 16 bits +0.051, 20 bits +0.020, 32 bits −0.001. Below zero the multi-resolution filter is cheaper.-0.20000.2000.4000.6000.8001filter bits a keymulti-resolution minus one length25810162032keys in 16 clustersuniform keyshalf the ranges in the gaps, half at the keysbelow zero: multi-resolution cheaper
Fig. 5 The multi-resolution filter’s transfers a range query minus one length a level’s, half the ranges in the gaps and half at the keys. Sixteen clusters: +0.939 at two bits a key, +0.010 at five, −0.164 at eight, −0.172 at ten, about −0.13 from sixteen to thirty-two. Uniform keys: +0.749, +0.516, +0.270, +0.172, +0.051, +0.020 and −0.001.

On sixteen clusters the multi-resolution filter overtakes one length a level between five and eight bits a key and stays ahead at every memory above, by 0.172 transfers a query at ten bits and about 0.13 from sixteen to thirty-two. At two bits a key it is far behind, 0.939 transfers, because eleven filters in two bits a key are too starved to say no reliably even with the clustered store’s economy of prefixes. At five bits it is level. On uniform keys it is behind at every memory up to twenty bits and ties at thirty-two, −0.001, within the noise of 600 ranges of each size. That is the earlier page’s result, reproduced on the mixed workload.

The gap between the two lines at high memory is the part that no amount of memory closes. At thirty-two bits a key both designs have filters reliable enough that false positives barely matter. On uniform keys the difference then goes to zero, because one well-chosen length serves every range. On sixteen clusters it stays at 0.13 transfers a query. That residue is the price of one length for two kinds of range, and it is a property of the workload rather than of the filter’s accuracy. The margin at ten bits, 0.172, is larger than that residue. The difference is plausibly the division of memory, which works better on clustered keys than on uniform ones; that split was argued from the two curves, not measured separately.

What decides it

The earlier page’s conclusion was that a store should choose its prefix length for each level and each memory, a choice cheap to make and expensive to avoid. On clustered keys that conclusion survives for any workload that asks ranges of one kind. The small levels’ share of a range filter found that each level wants its own length, and this page finds each workload does too. The two designs part only when the workload asks both kinds of range of one level. Then no length is right, and the design that holds several and chooses among them per query wins by as much as the single length’s compromise costs.

That is a stronger condition than clustering, and a store can check it. The runs a range query can skip chose one length for the whole store from the workload it measured, and the same measurement, split by kind of range, is enough here. The two kinds of range are distinguishable after the fact: a range that the oracle skips in every level fell in a gap, and one whose levels all hold keys fell in a cluster. A store that counts both over a recent window knows whether it has a single-kind workload, where one length is enough, or a mixed one on keys with empty regions, where it is not. The filter each run carries put the store’s filter memory where the lookups are. The same kind of accounting could choose between a filter design and its alternative.

The limits of the measurement

One shape of clustering. Clusters are windows of equal width, placed at random, filled uniformly, and together covering a sixteenth of key space. Clusters of unequal size, or clusters with dense cores and sparse edges, would give a different occupancy at the middle lengths. How much the result depends on the equal widths was not measured.

Three workloads, and one mix. Half the ranges start anywhere and half at a stored key. A workload asking nine in ten ranges at the keys would weight the compromise towards the keys’ lengths, and the multi-resolution filter’s margin would move. Only the half-and-half mix and the two pure workloads are measured.

Lengths chosen on the ranges they are charged on. Each single length is the best of fifteen, from 12 bits to 30, on the same 600 ranges of each size that it is then scored on, which flatters it slightly. The earlier page found that choosing on one set of ranges and charging on another moved the cost by under 1%. The margins that decide this page, 0.11 to 0.17 transfers a query on totals between 4.5 and 6.9, are larger than that.

Every stored prefix gets the same bits. The multi-resolution filter divides a level’s memory by distinct prefixes, as the earlier page’s did. A design that gave the fine lengths a larger share, since they carry the short ranges, might widen its margin; it is not measured.

Transfers, not probes. At ten bits a key on sixteen clusters, the multi-resolution filter asks 27 filter probes a query on the shortest ranges, where the compromise length asks 4, and 553 on the longest against 410. A Bloom probe is a few memory reads and a transfer is a disk block, so on a store on disk the transfers decide. The read a filter has no key for is where that exchange rate was first set, and a store in memory would weigh the probes differently.

Still open: two lengths chosen per level

The multi-resolution filter wins on a mixed workload with eleven lengths, of which the analysis above says two do almost all the work: a coarse one for the gaps and a fine one for the keys. On uniform keys a pair would have had nothing to do, since one length was enough there. On clustered keys and a mixed workload the pair has a job, and it holds its memory in two filters rather than eleven.

The measurement that follows gives each level two lengths, chosen together for the store, the workload and the memory, and asks a range at the coarse one first and the fine one only below a yes. It asks what share of the multi-resolution filter’s margin over one length the pair recovers, and at what memory. The prediction is that it recovers nearly all of it. The coarse length’s filter holds few prefixes on a clustered store and costs almost nothing, so nearly all the memory goes to the fine one, more than the fine length receives when it shares with twelve others. The pair should therefore beat the multi-resolution filter on the short ranges at the keys and match it in the gaps. It could fail on a store whose clusters come in two sizes. There a gap between large clusters and a gap between small ones want different coarse lengths, and only a design that holds a whole range of lengths can serve both.

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.

Block transferBloom filterDesign parameterFalse-positiveFalse-positive rateLsm treePer levelRange queryRead amplification