Chapter 11 · Probabilistic Data Structures and Approximate Analytics

Bloom Filters: Membership with False Positives, Capacity, Error Rate, and Scaling

Use Bloom filters as explicitly sized probabilistic membership prefilters and measure their false-positive behavior instead of assuming exact membership.

Intermediate165–195 minutesBloom capacity and false-positive labRedis Open Source 8.10.1Free/local-firstLast reviewed: September 6, 2026

Learning outcomes

AtlasMart wants to avoid expensive downstream work for product IDs that were definitely never seen before, while accepting a small number of “probably seen” responses. A Bloom filter is designed for exactly that asymmetric membership question.

01

Define Bloom false positives and the no-false-negative condition for an append-only correctly operated filter.

02

Reserve capacity and error rate explicitly instead of accepting accidental defaults.

03

Observe BF.ADD/BF.EXISTS/BF.INFO and distinguish configured error targets from measured trial outcomes.

04

Explain scalable sub-filters, NONSCALING behavior, and the cost of bad capacity estimates.

05

Reject Bloom filters when deletion or authoritative membership is required.

Exact lab baseline

All Chapter 11 mandatory labs reuse the disposable Chapter 01 environment: Redis Open Source 8.10.1 from Docker Official Image redis:8.10.1, container atlasmart-redis-ch01, standalone topology, host publication 127.0.0.1:6379, TLS disabled only because traffic stays on loopback, default ACL user disabled, named users atlasmart-app and academy-admin, logical database 0, AOF with appendfsync everysec plus RDB snapshots, persistent /data, and no explicit maxmemory limit or eviction policy. Redis 8 integrates Bloom filters, Cuckoo filters, Count-Min Sketch, Top-K, and t-digest into Redis Open Source; HyperLogLog remains a long-standing core Redis data type. Fixtures stay under atlasmart:ch11:*. Mandatory work is local and uses deterministic synthetic AtlasMart data; no paid service, production endpoint, or real credential is required.

Redis 8 integration and ACL/version discipline

Redis 8 integrated five probabilistic structures that historically lived in RedisBloom/Redis Stack: Bloom filter, Cuckoo filter, Count-Min Sketch, Top-K, and t-digest. Redis 8 also added ACL categories @bloom, @cuckoo, @cms, @topk, and @tdigest, while these commands also participate in broader @read/@write/@fast/@slow categories. That can widen an old ACL rule after an upgrade, so verify effective permissions rather than assuming module-era ACL behavior. Redis 8.10.1 is a security release and specifically fixes a Count-Min Sketch RDB-loading memory-safety issue and a Top-K cleanup issue; do not downgrade the chapter lab to an older moving tag.

1. Bloom answers “possibly present?” with asymmetric error

A Bloom filter hashes each inserted item into bits. If any required bit is absent, the item is definitely not in the filter. If all required bits are set, the item is probably present because unrelated inserts can collide onto the same bits. Correct append-only use therefore admits false positives but not false negatives.

BF.EXISTS result Interpretation Safe action
0 / false Definitely not added (or key absent/wrong-type behavior per command contract) Skip work that only makes sense for previously seen items
1 / true Probably added Verify against authoritative state if a false positive has business cost

2. Capacity and error rate are a design contract

BF.RESERVE key error_rate capacity creates a filter with an upper-bound false-positive target for its initial sub-filter. Redis documents the approximate bit cost per item as -ln(error_rate)/ln(2)^2: about 9.585 bits/item for 1%, 14.378 for 0.1%, and 19.170 for 0.01%, before object/sub-filter overhead.

redis-cli · reserve a bounded AtlasMart filter
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:bloom:productsdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.RESERVE atlasmart:ch11:bloom:products 0.01 1000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products

Do not choose 0.000001 because it “sounds safer” without calculating memory and CPU consequences. Start from the cost of a false positive and expected cardinality.

3. BF.ADD return is itself probabilistic

redis-cli · add and query membership
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.ADD atlasmart:ch11:bloom:products product:1001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.ADD atlasmart:ch11:bloom:products product:1002docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.ADD atlasmart:ch11:bloom:products product:1001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.EXISTS atlasmart:ch11:bloom:products product:1001docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.EXISTS atlasmart:ch11:bloom:products product:9999

A repeated BF.ADD commonly returns 0 because the item probably already existed, but the probabilistic structure cannot turn that return into exact duplicate detection. If duplicate acceptance/rejection is contractual, maintain exact state.

4. False-positive trials need absent ground truth

To measure false positives, you must know that queried candidates were never inserted. A useful experiment has two disjoint deterministic namespaces: insert known:0000..0999, then query absent:0000..9999. Count positive results among the absent set and report false_positives / absent_trials. A single short run can land above or below the configured target by chance.

python · trial design and confidence discipline
inserted={f"known:{i:04d}" for i in range(1000)}absent=[f"absent:{i:04d}" for i in range(10000)]assert not inserted.intersection(absent)# Feed inserted values to Redis BF.ADD/BF.MADD, then query absent values.# Do not fabricate a rate here: record what your server actually returns.false_positives = 0   # replace with measured positives among absent[]rate = false_positives / len(absent)print("measured false-positive rate:", rate)print("configured target:", 0.01)

5. BF.INFO proves capacity, allocated bytes, sub-filters, and item bookkeeping

redis-cli · inspect Bloom structure
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products CAPACITYdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products SIZEdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products FILTERSdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products ITEMSdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:products EXPANSIONdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch11:bloom:products

BF.INFO SIZE reports bytes allocated by the Bloom implementation; MEMORY USAGE is Redis key memory accounting. They answer related but not necessarily identical accounting questions.

6. Scaling is convenient, not free

By default, when the initial capacity is reached Redis can add sub-filters. The default expansion factor is 2. More sub-filters increase query work and memory overhead, which is why Redis recommends reserving a realistic initial capacity. Use NONSCALING only when a hard capacity and insert failure are acceptable.

redis-cli · scaling versus hard capacity
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:bloom:scaling atlasmart:ch11:bloom:fixeddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.RESERVE atlasmart:ch11:bloom:scaling 0.05 10 EXPANSION 2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.RESERVE atlasmart:ch11:bloom:fixed 0.05 10 NONSCALINGdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:scalingdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app BF.INFO atlasmart:ch11:bloom:fixed

Populate both with a controlled loop on your machine and observe when the fixed filter refuses additional inserts versus when the scaling filter adds a sub-filter.

7. Bloom does not support deletion

Bits are shared among multiple hashed elements. Clearing bits for one element could create false negatives for other elements, so the Redis Bloom API has no item-delete command. If AtlasMart must retract membership, use an exact Set or consider a Cuckoo filter with its stricter deletion preconditions.

8. Wrong approach: use Bloom as a fraud deny-list

If BF.EXISTS returns “probably present” and the application automatically blocks a customer, a false positive becomes a user-impacting security decision. Repair the design by using Bloom only as a fast prefilter and confirming positives against authoritative deny-list state before enforcement.

9. Wrong approach: guess capacity and ignore expansion

A filter reserved for 100,000 IDs but fed tens of millions may create many sub-filters. Even if it keeps functioning, query CPU and total false-positive behavior differ from the original small design. Track BF.INFO FILTERS, ITEMS, allocated bytes, observed positive rate, and insert throughput.

10. ACL upgrade boundary matters in Redis 8

Because Redis 8 integrated probabilistic commands into broader ACL categories, an application user with +@read +@write can gain access to commands that did not exist in the same categories on an older deployment. Use explicit category/command policy where least privilege matters, and re-run ACL DRYRUN during upgrades.

11. Reproducible cleanup

redis-cli · remove Bloom fixtures
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:bloom:products atlasmart:ch11:bloom:scaling atlasmart:ch11:bloom:fixed

12. Production judgment

Bloom filters fit cheap negative membership checks, cache-admission hints, duplicate-work avoidance, and “probably seen” gates where positives can be verified. Size from expected cardinality and tolerated false-positive cost; measure actual false-positive rate, filter count, memory, CPU, persistence footprint, and saturation. Do not use Bloom where deletion, exact membership, enumeration, or safety-critical authorization is required.

13. Summary and next step

Bloom filters trade exact positive membership for compact append-only state and a configurable false-positive budget. Lesson 3 introduces Cuckoo filters, which add deletion and approximate multiplicity—but deletion must be used with discipline to avoid creating false negatives.

Check your understanding

  1. What does BF.EXISTS returning 0 mean?
  2. What does returning 1 mean?
  3. Why reserve capacity explicitly?
  4. Can a Redis Bloom filter delete one item?
  5. Why must positives be verified for a deny-list?
Review the answers

Under correct operation the item was definitely not added (subject to command key/wrong-type semantics).

The item was probably added; false positives are possible.

To control memory, hash count, sub-filter growth, CPU, and the intended error budget.

No item-deletion command exists for Bloom filters.

Because a false positive would otherwise become an incorrect enforcement decision.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.