Quant Memo
Core

Bloom Filters

A compact data structure that answers "have I seen this before?" using a fraction of the memory a full set would need, at the cost of occasionally saying yes when the answer is actually no.

Prerequisites: Hash Maps and Sets

A market-data cache needs to check, millions of times a second, whether a given order ID has already been processed — but storing every order ID ever seen, forever, in a hash set eats memory that grows without bound. A Bloom filter answers "have I definitely not seen this, or possibly seen this?" using a fixed, small block of memory, trading a small, tunable false-positive rate for that saved space.

A Bloom filter is a bit array plus several hash functions. Adding an item flips several bits to 1; checking an item asks whether those same bits are all 1. It can never wrongly say "no" — only, occasionally, wrongly say "yes."

How it works

Start with a bit array of size mm, all zeros, and kk independent hash functions, each mapping an item to a position in that array.

To add an item: compute its kk hash values, and set the bit at each of those kk positions to 1.

To check an item: compute the same kk hash values. If any of those bits is 0, the item was definitely never added — a bit that's still 0 could only mean nothing ever touched it. If all kk bits are 1, the item is probably in the set — but those bits could have all been set by other items' overlapping hashes, so it might be a false positive.

bit array (16 slots) order A (blue) sets bits 1, 4, 8 order B (amber) sets bits 2, 6, 12 query "order C" (red) checks bits 4, 6, 8 — all already 1 filter says "probably seen" — but C was never added
Two real inserts happen to cover all three bits a third, never-inserted item hashes to — a false positive. False negatives are impossible; false positives are the price of the compression.

Worked example

Take m=100m = 100 bits and k=3k = 3 hash functions, with 10 items already inserted. The fraction of bits still 0 is about ekn/m=e0.374%e^{-kn/m} = e^{-0.3} \approx 74\%. The false-positive rate — probability all kk bits for a never-inserted item are 1 — is roughly (1ekn/m)k(0.26)31.7%(1 - e^{-kn/m})^k \approx (0.26)^3 \approx 1.7\%. Doubling mm to 200 bits drops that to about 0.34%0.34\%: more bits, fewer accidental collisions.

What this means in practice

Bloom filters guard expensive lookups: a database checks one before touching disk to see if a key might exist, LevelDB and Cassandra use them to skip SSTables that can't contain a queried key, and a trading system might use one to filter "have I already routed this order ID" before a slower, authoritative check. The false-positive rate is tunable via mm and kk; no tuning removes it entirely, only shrinks it.

A Bloom filter cannot delete items — flipping a bit back to 0 could unset a bit another item also relies on, silently turning a true "yes" into a false "no," which breaks the one guarantee the structure has. Deletion requires a variant like a counting Bloom filter, which trades more memory for that ability.

Related concepts

Practice in interviews

Further reading

  • Bloom, 'Space/Time Trade-offs in Hash Coding with Allowable Errors' (1970)
  • Broder & Mitzenmacher, 'Network Applications of Bloom Filters: A Survey'
ShareTwitterLinkedIn