Concept

Per level — where it appears

Accounted separately for each level of a layered structure rather than for the structure as a whole. Allocating memory or error level by level lets the small levels get more of it where it buys the most, which a single setting for the whole structure cannot do.

Named by 14 essays across 3 fields — each of them below, with the objects they name alongside it.

0.020.050.10.20.5121235810filter bits a keywasted reads per absent lookupno filters: all 3 levelssame rate every levelrates sized to levelsn = 65,536, size ratio 4, first run 1,024 keysthe same memory at every point

The filter each run carries

A log-structured store turns every lookup for a missing key into a read of every level, and a Bloom filter on each run buys those reads back with memory. Spread five bits a key evenly across three levels and a missing key still wastes 0.279 reads. Give the small levels more bits and the large one fewer — the same memory — and it wastes 0.201. At four levels the gap is 0.382 against 0.209, because sized filters stop the waste growing with the number of levels.

applied · Transfer
235810filter bits a key, averaged over the storetransfers a query3.804.204.605.00one length, even bitsa length each, even bitsa length and bits eachthe oraclemixed workload, 2^20 keys, four levelsdotted: the oracle

The small levels' share of a range filter

Prefix filters on a four-level store were proposed a prefix length each, on the reasoning that one length is a compromise between levels whose densities differ 43-fold. Each level does want its own length, 18 to 22 bits, and that recovers a quarter of the gap to a perfect range filter. The gap is mostly not about length. Three fifths of it is false positives. Moving filter bits from the largest level to the small ones — 12, 12, 8 and 3 bits a key instead of 5 each — recovers more than half of it at the same memory, and matches one shared length given twice the memory.

applied · Transfer
456filter bits a key, over the whole storetransfers a range query258101216203216 to 24 bits, asked where it fits16 to 24 bits, asked at everylengthone length, chosen for five bitsone length, chosen for each memorythe oraclefour levels, 2^20 keysdotted: the oracle

The resolution a range filter can afford

A prefix filter on each level of a log-structured store answers a range by asking one question for every prefix the range touches, and each can be wrong. A filter holding prefixes at every length from 16 to 24 bits could ask each range at the resolution it needs, and was proposed as the repair. At the store's five bits a key it costs 5.69 transfers a range query where one length a level costs 4.32, because a short range is asked only at the finest length, and that filter now holds a fraction of the memory. Asked at every length it recovers most of that, and seems to overtake the single length at twelve bits a key — but only a single length chosen for five bits. Chosen again for each memory, one length a level beats every multi-resolution design at every memory measured, because the resolution a level can afford is itself set by its memory.

applied · Transfer
-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

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.

applied · Transfer
-0.300-0.200-0.10000.1000.2000.300filter bits a keytransfers a query saved against one length a level41024the best pair a levelmulti-resolutionhalf the ranges in the gaps, half at the keysabove zero: cheaper than one length

Two lengths that do the work of eleven

On keys that cluster, asked both between the clusters and at them, a prefix filter holding every length from 12 to 24 bits beat one length a level by 0.17 transfers a range query, and a pair of lengths — one coarse, one fine — was proposed to recover nearly all of that. It recovers more than all of it: 0.23 transfers at ten bits a key, and at four bits, where the eleven lengths lose to one, the pair still saves 0.18. The coarse filter takes under 2% of a level's memory, and the eleven-length filter was leaving its finest length as little as 14% and cannot give it more without starving the lengths its descent passes through. The store predicted to defeat a pair, with gaps at two scales, does not. The saving is bought in questions: the pair asks its filters more often than the eleven lengths do.

applied · Transfer
shuffled arrivals036925%50%75%100%one cluster at a time036925%50%75%100%share of the 2^20 keys inserteddark: chosen each write · olive: chosen once · orange: none · green: perfect10 bits a key; transfers a range querychosen once: 12 and 22 bits

The filter rebuilt with every write

A log-structured store chooses a range filter's two prefix lengths when it writes a level, and a filling store's small levels hold only the keys that arrived last. Choosing at every write was predicted to keep the lead a pair chosen once on the full store has, except where keys arrive a cluster at a time and a small level's choice goes stale when the next batch lands elsewhere. It cannot go stale: a levelled store changes a level's keys only by rewriting it, and rewriting it rebuilds the filter. Choosing at every write and choosing once then differ by at most 2.3% of what a perfect filter saves, on both arrival orders, at two bits a key and at ten, and choosing costs twenty-eight times the hashing. What the order of arrival changes is the store: filled a cluster at a time, its small levels hold one cluster each, and at two bits a key the same filter captures 94% of a perfect filter's saving against 68% shuffled.

applied · Transfer
50%60%70%80%90%100%the store's fill, share of its 1,048,576 keysshare of a perfect filter's saving captured13%25%38%50%75%100%a cluster at a time, dividedshuffled, divideda cluster at a time, evenshuffled, even2 bits a key on averagedashed: the same bits on every level

One bit a key, divided

A levelled store of a million clustered keys, each level's range filter a pair of prefix lengths chosen when the level is written, captures 68% of a perfect filter's saving at two bits a key spread evenly when its keys arrive shuffled, and 94% when they arrive a cluster at a time. The proposal was to divide the memory by what each level's filter saves per bit, and it predicted the memory would leave the small levels, whose keys the arrival order had already sorted out. It goes the other way, as it did for single prefix lengths, and much further: the small levels take twelve to sixteen bits a key, the deepest level one, and the store captures 99% of a perfect filter's saving on both orders while leaving part of the budget unspent. Divided, one bit a key on average does what four bits spread evenly cannot.

applied · Transfer
40%60%80%100%shuffled, 0.5 bits a keyshuffled, 1 bits a keyshuffled, 2 bits a keyshuffled, 4 bits a keya cluster at a time, 0.5 bits a keya cluster at a time, 1 bits a keya cluster at a time, 2 bits a keya cluster at a time, 4 bits a keybar: even split · large dot: fitted · dark dot: rule, δ chosen · small dot: rule, δ = 4charged on unseen queriesshare of the saving

A division chosen before the queries arrive

A levelled store's range-filter memory, divided among its levels by trying every assignment against the store's own queries, captures 99% of a perfect filter's saving on both arrival orders, with the small levels at twelve to sixteen bits a key and the deepest at one. A store writing a level cannot try every assignment, but it knows its levels' sizes, and a rule giving each level δ more bits a key for every factor of four it is smaller was predicted to match the fitted division on the shuffled store and to land near the even split's 94% on the store filled a cluster at a time. It matches the fitted division on both: 97.2% to 99.0% shuffled and 99.7% to 99.9% filled a cluster at a time from one bit a key up, with δ chosen on a sample of queries and charged on others. One δ of four, set before any query, is within a point and a half everywhere from one bit a key up. The rule fails exactly where the proposal said: a δ of six or more at one bit a key gives the deepest level nothing, and the shuffled store falls from 97.2% to 73.9%.

applied · Transfer
0.4000.6000.8001share of the keys arrivedshare of a perfect filter's saving1/81/43/81/23/41fitted to the queriesthe size rule, δ = 4the even splitthe shuffled store, 1 bit a keycharged on unseen queries

The sizes a store passes through

A levelled store's range-filter memory can be divided by its levels' sizes alone, a few more bits a key for every factor of four a level is smaller than the deepest, and on the full store that rule matched the division fitted to the store's own queries at every budget. Through the fill it does not. At a bit a key or less it falls up to 17 points of a perfect filter's saving behind on the shuffled store and 26 on the store filled a cluster at a time, and every large loss has the same cause: part way through the fill the deepest level is a smaller share of the store, and the rule gives it nothing.

applied · Transfer
0.6000.8001share of the keys arrivedshare of a perfect filter's saving1/81/43/81/23/41fitted to the queriesthe rule, floor of half a bitthe rule, no floorthe shuffled store, 1 bit a keycharged on unseen queries

A floor under every level

A levelled store's filter memory divided by its levels' sizes lost up to 26 points of a perfect filter's saving part way through its fill, every large loss a level given no filter at all. A floor of half a bit a key under every level was predicted to close every gap above five points at one bit a key and cost nothing at two and four. It closes them: the worst gap at one bit falls from 17 points to 4 on the shuffled store and from 25 to under 1 on the clustered one, and nothing moves at two bits and up. At half a bit a key the floor is the whole budget and the rule becomes the even split, which the clustered store wants half way through and the shuffled store, at the same sizes, loses 35 points by.

applied · Transfer
shuffled, 0.5 bits a key34.8 span34.8 flooredshuffled, 1 bits a key2.3 span4.1 flooredshuffled, 2 bits a key4.1 span4.2 flooredshuffled, 4 bits a key4.1 span4.1 flooredclustered, 0.5 bits a key9.1 span9.1 flooredclustered, 1 bits a key29.6 span0.9 flooredclustered, 2 bits a key30.7 span0.7 flooredclustered, 4 bits a key30.4 span0.6 flooredworst points behind the fitted division over the filltwo orders, four budgetssix checkpoints

A span the queries do not see

A rule for dividing a levelled store's range-filter memory by its levels' sizes, with a floor of half a bit a key, came within five points of the division fitted to the store's own queries at every budget from one bit up — but at half a bit the shuffled and the clustered store wanted opposite divisions of identically sized levels. A level's fences, its first and last keys, say how much of the key space it spans, and a clustered level spans little. Scaling each level's bits by that span was predicted to close the half-bit gap and change nothing above. It changes nothing at half a bit — where the floor is the whole budget, so there is nothing left to scale — and from one bit up it puts the clustered store 30 points behind the fitted division, where the floored rule was within one. A level holding one cluster spans 0.4% of the key space and meets 4.4% of the queries, because half of them start at a stored key: the fences measure the key space, and the queries are aimed at the keys.

applied · Transfer
02e+34e+36e+301234567891011level of the wavelet treebitsplainblock-codedrun-coded3,612 points · 12 levels24 copies of 2048 characters

The level where compression stops paying

Choosing the best coding for every level of the grid separately, rather than one for all twelve, saves 26 bits out of 47,668 — five hundredths of one per cent. The apparatus for choosing costs more than that to describe.

wrong · Grid
00.2500.5000.750101020304050thousands of bitsrectangles counted exactlythe floorcut to d levels, the index'scut to d levels, drawnevery k-th point, the index'severy k-th point, drawnexact: right to the nearest point3,612 points

A count that names every point

A grid that can report the points in a rectangle can be no smaller than log₂(z!) bits, because reporting them recovers the permutation. A grid that only counts them was left open as possibly smaller. Exactly, it cannot be: counts alone decode every point, and on the phrase index's 3,612 points 42,860 count questions recover the whole permutation, so an exact counter pays the same floor of 37,485 bits. Approximately it can — and the rectangles a phrase index asks are where an approximate count is worst. They hold 2.6 points on average and a third of them hold exactly one; the wavelet grid cut to eight of its twelve levels, 8% under the floor, counts 46% of them right.

indexes · Grid
00.2500.5000.750124681012levels of the grid keptshare of splitsnine in tenempty splitsturned awayoccupied splitsanswered yes4,300 bits a level with its directorythe rest: maybe

A test that is the top of the search

A phrase index asked whether a pattern occurs only needs to know, split by split, whether a rectangle of its grid holds a point. Stopping the grid's descent at six of its twelve levels was predicted to turn away nine in ten of the splits that come to nothing, for half the grid's bits. It turns away three in four, and the ones it lets through sit a median of five rows from a point. The test is never wrong, but the existence query had little left for it to save: patterns that occur are settled by their first split 94% of the time, and most patterns that do not occur never reach the grid.

indexes · Grid

Named alongside it

The objects these essays reach for when they reach for this one.

Bloom filterLsm treeDesign parameterRange queryRead amplificationBlock transferSpace accountingFalse-positiveFalse-positive ratePredictionTrade offDeferral

All concepts