Bloom filters

Topics in this section
2 cards

Bloom filters: 'definitely not' or 'maybe'

A Bloom filter answers 'have I seen this item?' using very little memory, at the price of occasional mistakes in one direction. It's a bit array, all zeros at the start, plus k hash functions. To add an item, hash it k times and set those k bits to 1. To check an item, hash it the same way: if any of its bits is 0, it was definitely never added. If all are 1, it was probably added.

The 'probably' is because other items may have set those same bits. So a Bloom filter can give false positives but never false negatives. It can't list its items, and plain Bloom filters can't delete them (clearing a bit could erase another item).

A bit array of 12 bits; two items set three bits each; a third item hits a zero bit and is definitely absent
In real life

Databases like Cassandra and RocksDB keep a Bloom filter per data file on disk: before reading a file to look for a key, they ask the filter, and skip the read when the answer is 'definitely not'. Most lookups for missing keys never touch the disk.

In code: Python · Rust
import hashlib
class Bloom:
    def __init__(self, m=1024, k=3):
        self.m, self.k, self.bits = m, k, bytearray(m)
    def _idx(self, item):
        for i in range(self.k):
            h = hashlib.sha256(f"{i}:{item}".encode()).digest()
            yield int.from_bytes(h[:8], "big") % self.m
    def add(self, item):
        for i in self._idx(item): self.bits[i] = 1
    def maybe_contains(self, item):
        return all(self.bits[i] for i in self._idx(item))
  • This sketch uses a byte or bool per bit for clarity; real filters pack 8 bits per byte.
  • Libraries pick m and k from the expected item count and the false-positive rate you can accept.
Check yourself

A Bloom filter says an item is NOT in the set. How much can you trust that?

Sizing and using a Bloom filter

The false-positive rate depends on how full the bit array is. More bits per item means fewer collisions. A common rule of thumb: about 10 bits per item with about 7 hash functions gives roughly a 1% false-positive rate. Compare that with storing each item: a URL might take 50–100 bytes, while the filter needs about 1.2 bytes per URL.

As you add items beyond what the filter was sized for, more bits become 1 and the false-positive rate climbs towards 100%. So you size the filter for the expected number of items in advance. Use a Bloom filter as a cheap first check in front of something expensive and exact, never as the final answer when a wrong 'yes' matters.

In real life

A web crawler checks 'have I already visited this URL?' against a Bloom filter. A false positive means one page is skipped, which is acceptable. For 'has this payment already been processed?', a false positive would wrongly reject a payment, so the filter can only decide when to look in the real database.

Check yourself

A Bloom filter was sized for 1 million items and now holds 10 million. What happens?