open atlas
↑ Back to track
System Design Foundations SD · 08 · 03

Bloom filters

A bloom filter answers 'maybe present, or definitely absent?' in a tiny bit-array with no false negatives. It trades a tunable false-positive rate for huge space savings, letting a cache or DB skip lookups that would certainly miss — at the cost of an occasional empty lookup.

SD Middle ◷ 18 min
Level
FoundationsJuniorMiddleSenior

A storage engine was spending most of its read latency on lookups that returned nothing. A read for a key would check several on-disk files in turn, and for keys that didn’t exist anywhere, it paid a disk seek per file only to confirm “not here.” The fix wasn’t a faster disk or more RAM for the index — both were too expensive at that data size. It was a tiny structure, a few bits per key, that could say with certainty “this key is definitely not in this file, don’t bother reading it.” It was sometimes wrong in the cheap direction — occasionally it said “maybe” and the read came back empty — but it was never wrong in the expensive one. That asymmetry is the entire idea of a bloom filter.

The one-sided guarantee

A bloom filter is a probabilistic set-membership structure. You add elements to it, and later ask “is X in the set?” It answers with one of two verdicts, and the asymmetry between them is the whole point:

  • “Definitely not present.” This answer is always correct. A bloom filter never has false negatives — if it says an element was never added, it really wasn’t.
  • “Possibly present.” This answer might be wrong. There is a tunable probability of a false positive: the filter says “maybe” for an element that was never added.

So a bloom filter is a fast, cheap, sometimes-wrong-in-the-safe-direction pre-check. It can’t store the elements themselves and can’t enumerate them — it only answers membership, approximately. The payoff is space: it represents a set in a tiny fraction of the memory the actual elements would take, which is why it’s used as a guard in front of an expensive exact lookup.

The mechanism: a bit-array and k hashes

A bloom filter is a bit-array of m bits, all starting at 0, plus k independent hash functions, each mapping an element to one of the m positions.

To add an element: hash it with all k functions to get k positions, and set those k bits to 1.

To query an element: hash it with the same k functions and check those k positions. If any of them is 0, the element was definitely never added → “definitely not present.” If all k are 1, the element is “possibly present” — but those bits might have been set to 1 by other elements that happen to share those positions. That coincidence is the false positive.

m-bit array (m = 16, k = 3 here)

add "alice"  → hashes to bits 2, 7, 13   → set them
add "bob"    → hashes to bits 4, 7, 11   → set them
                                            (bit 7 now shared)

index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
bit:   0 0 1 0 1 0 0 1 0 0 0  1  0  1  0  0

query "carol" → bits 2, 4, 13 → ALL are 1 → "possibly present"
                (but carol was never added — FALSE POSITIVE,
                 her three positions were each set by alice/bob)
query "dave"  → bits 3, 8, 15 → bit 3 is 0 → "definitely NOT present"

This is why there are no false negatives: adding an element only ever sets bits, never clears them, so a previously-added element always finds all its bits at 1. And it’s why false positives exist: as more elements are added, more bits flip to 1, and eventually an unrelated element’s k positions can all already be set.

The false-positive rate: size, count, and k

The false-positive probability is not a fixed property — you tune it. It depends on three numbers: m (bits in the array), n (elements inserted), and k (number of hash functions). The intuition: more bits per element (m/n) means fewer collisions and a lower false-positive rate; too few or too many hash functions both hurt (too few and each element discriminates poorly; too many and you fill the array too fast). For a target false-positive rate there is an optimal k, and the rough engineering rule is that you need on the order of ~10 bits per element for a ~1% false-positive rate — and adding ~5 bits per element cuts the rate by roughly another order of magnitude. The headline is the space win: ~1.2 bytes per element to guard a set, versus storing the full keys.

A hard constraint: you must size the filter for the number of elements you’ll insert. Keep adding past the planned n and the bit-array saturates (too many 1s), the false-positive rate climbs toward 100%, and the filter becomes useless — it says “maybe” to everything. There is no “just resize” for a plain bloom filter; you rebuild a larger one (or use a scalable variant).

Why this works

Why can’t a standard bloom filter support deletion? Deleting “alice” would mean clearing her bits 2, 7, 13. But bit 7 was also set by “bob” — clearing it would make a query for “bob” find a 0 and wrongly report “definitely not present,” a false negative, which breaks the entire guarantee the structure is built on. Because bits are shared, you can’t tell which element a 1 belongs to, so you can’t safely clear it. This is the central limitation, and it’s exactly what the counting bloom filter fixes: replace each bit with a small counter (say 4 bits), increment on add and decrement on remove. Now bit 7 holds 2 (alice + bob), removing alice decrements it to 1, and bob is still found. The cost is ~4× the memory — you trade space to buy deletion.

Where they earn their keep

Bloom filters appear wherever a “definitely-not-here” answer lets you skip an expensive operation:

  • LSM-tree databases (Cassandra, RocksDB, LevelDB, HBase) put a bloom filter on each on-disk table file so a read for a missing key skips the disk seeks for files that certainly don’t contain it — the storage-engine story from the hook.
  • Caches use a filter to avoid querying the backing store for keys that were never cached (and to fight cache-penetration attacks that hammer the DB with known-missing keys).
  • CDNs and “one-hit-wonder” detection: a CDN can use a filter to avoid caching content requested only once, saving cache space for items likely to be requested again.
  • Web crawlers check “have I already seen this URL?” against a filter instead of a giant set, accepting that they’ll occasionally skip a new URL (here a false positive means a missed page — sometimes acceptable, sometimes not).

Together these use-cases share one shape: the filter lives in front of something expensive, and a “definitely absent” verdict skips that expense entirely; the occasional false positive just triggers one wasted lookup. The cuckoo filter is a newer alternative that supports deletion and can be more space-efficient at low false-positive rates, at the cost of a more complex insert that can fail when the structure is too full. Counting and cuckoo are the two variants to reach for when plain-bloom’s no-delete limitation bites.

Common mistake

Using a bloom filter where a false positive is unacceptable. The structure’s contract is “no false negatives, some false positives” — so it is only safe when a false positive is cheap, i.e. it triggers a fallback that confirms the truth. A filter guarding a database read is fine: a false positive just means one occasionally-wasted lookup that returns empty. But never use a bloom filter as the sole authority for a decision where a wrong “yes” causes harm — “has this user already used this one-time coupon?”, “is this transaction a known duplicate?” A false positive there would wrongly reject a legitimate action. The rule: a bloom filter is a fast pre-filter in front of ground truth, never the ground truth itself.

Quiz

A bloom filter returns 'possibly present' for key X. What can you correctly conclude?

Quiz

A team needs to remove elements from their bloom filter as items expire, but deletions are corrupting lookups. What's going on and what's the right structure?

Complete the analogy

A bloom filter is safe to use as a pre-check precisely because it never produces a false _______ — if it says an element is absent, that is always true — so its only error is occasionally saying 'maybe' for something that isn't there, which just triggers a harmless fallback lookup.

Recall before you leave
  1. 01
    Describe the add and query mechanism and why there are no false negatives.
  2. 02
    What controls the false-positive rate, and what's the rule of thumb?
  3. 03
    Why can't a standard bloom filter delete, and what are the variants?
Recap

A bloom filter is a probabilistic membership structure with a one-sided guarantee: “definitely absent” is always correct (no false negatives), while “possibly present” carries a tunable false-positive rate. The mechanism is an m-bit array plus k hash functions: adding sets k bits, querying checks them — any 0 means definitely absent, all 1 means maybe (those bits could belong to other elements). The false-positive rate is set by m, n, and k, with a rule of thumb of ~10 bits/element for ~1%, and you must size for n or the array saturates. The killer use is read avoidance: an LSM-tree database, a cache, a CDN, or a crawler consults the tiny filter first and skips the expensive lookup for keys that are definitely absent, paying only an occasional wasted lookup on a false positive. A standard filter can’t delete (shared bits) — that’s what the counting bloom filter (counters per slot) and cuckoo filter are for. And the governing rule: a bloom filter is a fast pre-filter in front of ground truth, safe only where a false positive is cheap — never the sole authority for a decision where a wrong “yes” does harm. Now when you see a database read path that looks expensive even for non-existent keys — ask whether a bloom filter sits in front of the disk lookup; in LSM-tree stores like RocksDB or Cassandra, that filter is precisely what keeps a missing-key read from touching disk at all.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 7 done
Connected lessons

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.