Chapter 11 · Probabilistic Data Structures and Approximate Analytics
HyperLogLog for Approximate Cardinality: PFADD, PFCOUNT, PFMERGE, and Error Tradeoffs
Estimate distinct AtlasMart cardinality with HLL while preserving exact ground truth, merge semantics, and explicit error boundaries.
Learning outcomes
AtlasMart wants a daily count of distinct visitors across millions of page-view events. Keeping every visitor ID in a Set answers exactly, but cardinality and memory can grow with traffic. HyperLogLog (HLL) deliberately discards element identity and keeps only compact state that estimates cardinality.
Define cardinality, exact ground truth, approximation error, standard error, and merge semantics before using PF commands.
Use PFADD/PFCOUNT and interpret return values without pretending they reveal exact novelty.
Compare HLL memory behavior with an exact Set on the same bounded AtlasMart fixture.
Merge daily HLLs with PFMERGE while preserving a separately measured exact baseline.
Decide when approximately 0.81% standard error is operationally acceptable and when exact state is required.
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 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. Cardinality is a count of distinct identities
Cardinality is the number of distinct elements
in a collection. For AtlasMart analytics, repeated page views
from one visitor should contribute one distinct visitor, not
many events. An exact Redis Set stores members and can answer
SCARD; an HLL does not retain recoverable member
identities and therefore cannot answer membership or deletion
questions.
| Question | Exact structure | Probabilistic structure | What is lost |
|---|---|---|---|
| How many distinct visitors? | Set + SCARD | HyperLogLog + PFCOUNT | Individual membership identity |
| Was visitor u42 seen? | Set + SISMEMBER | Not supported by HLL | Membership query |
| Remove visitor u42 from the estimate | Set + SREM | Not supported by HLL | Deletion/reversal |
| Union unique visitors across days | SUNION/SCARD | PFMERGE or multi-key PFCOUNT | Exact member list |
2. Redis HLL error and memory are bounded differently from exact Sets
Redis documents a standard error of approximately 0.81% for HyperLogLog cardinality. A dense Redis HLL uses about 12 KiB for its register array plus overhead, while small HLLs can use a sparse encoding before switching to dense. The important design property is that HLL memory does not grow linearly with unique visitor count the way an exact Set does.
Standard error describes the estimator, not a promise that every individual PFCOUNT result lies inside ±0.81%. Validate error distributions on data shapes representative of your workload.
3. Preflight the actual Redis 8 command surface
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO serverdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO PFADD PFCOUNT PFMERGE BF.RESERVE CF.RESERVE CMS.INITBYPROB TOPK.RESERVE TDIGEST.CREATEdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin ACL DRYRUN atlasmart-app PFADD atlasmart:ch11:hll:test u01
COMMAND INFO is stronger evidence than assuming an
old “RedisBloom module” packaging model. On Redis 8.10.1 the
five formerly module-centric probabilistic families are
integrated into Redis Open Source. HLL commands remain core
Redis commands.
4. Build exact and approximate state side by side
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:visitors:exact atlasmart:ch11:visitors:hlldocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch11:visitors:exact u01 u02 u03 u01 u04 u05 u02 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFADD atlasmart:ch11:visitors:hll u01 u02 u03 u01 u04 u05 u02 u06 u07 u08 u09 u10 u11 u12 u13 u14 u15docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SCARD atlasmart:ch11:visitors:exactdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:visitors:hlldocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch11:visitors:exactdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch11:visitors:hll
On a tiny fixture the HLL estimate may equal the exact count. That coincidence does not make HLL exact. Record both results and the two memory measurements; repeat with larger deterministic datasets when evaluating the tradeoff.
5. PFADD return value is not “this exact element was new”
PFADD returns 1 when at least one internal HLL
register changed, and 0 otherwise. Because HLL stores compressed
estimator state rather than exact members, a return of 0 does
not prove that the submitted visitor was previously seen, and a
return of 1 is not an exact membership log.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFADD atlasmart:ch11:visitors:hll u16docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFADD atlasmart:ch11:visitors:hll u16docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:visitors:hll
6. PFCOUNT can itself mutate cached HLL metadata
Redis documents PFCOUNT as technically able to
modify the HLL because cached cardinality is stored in its
representation. Treat it as a cardinality query at the
application level, but understand why
ACL/replication/persistence diagnostics may show details that
surprise someone expecting a physically read-only object.
7. Merge daily sketches without summing daily counts
Summing per-day PFCOUNT values double-counts visitors who appear
on multiple days. Merge the estimator states instead.
PFMERGE writes a destination HLL representing the
union; multi-key PFCOUNT can estimate a temporary
union without persisting a destination.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:hll:day1 atlasmart:ch11:hll:day2 atlasmart:ch11:hll:two-daysdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFADD atlasmart:ch11:hll:day1 u01 u02 u03 u04docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFADD atlasmart:ch11:hll:day2 u03 u04 u05 u06docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:hll:day1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:hll:day2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:hll:day1 atlasmart:ch11:hll:day2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFMERGE atlasmart:ch11:hll:two-days atlasmart:ch11:hll:day1 atlasmart:ch11:hll:day2docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app PFCOUNT atlasmart:ch11:hll:two-days
The exact union for this fixture is six visitors. Use that only as ground truth for the test; never “correct” production HLL output to six because the fixture happened to be small.
8. Cluster locality changes multi-key HLL operations
In Redis Cluster, multi-key commands are constrained by hash
slots. If you intend to merge related HLLs server-side, design
co-location deliberately—for example
atlasmart:{visitors}:2026-09-05 and
atlasmart:{visitors}:2026-09-06 share the same hash
tag. Co-location can also create hot slots, so it is a workload
tradeoff, not a universal naming rule.
9. Exact local ground truth belongs beside the estimator
from collections import Counterfrom math import ceil# Deterministic AtlasMart fixture. Redis is not involved in this exact baseline.events = [ "u01","u02","u03","u01","u04","u05","u02","u06","u01","u07", "u08","u09","u10","u03","u11","u12","u13","u01","u14","u15",]exact_unique = len(set(events))exact_freq = Counter(events)print("exact unique:", exact_unique)print("u01 exact frequency:", exact_freq["u01"])print("top exact:", exact_freq.most_common(5))# For a quantile ground truth, pick an explicit rank convention and document it.latencies = sorted([18,21,19,23,22,24,25,20,28,31,26,27,35,29,30,42,38,33,40,55])def nearest_rank(q): i=max(0,min(len(latencies)-1,ceil(q*len(latencies))-1)) return latencies[i]for q in (0.5,0.9,0.99): print(q, nearest_rank(q))
10. Wrong approach: publish PFCOUNT as an exact billing number
Suppose finance charges merchants per distinct customer and the invoice says “1,000,000 exact customers” because PFCOUNT returned 1,000,000. The data structure does not provide that guarantee. Use exact source-of-record data for contractual accounting, or explicitly define the metric as an estimate with an accepted error policy.
Keep HLL for fast dashboards/capacity signals, periodically reconcile it against an exact sample or warehouse count, graph relative error, and alert if observed error exceeds the product’s acceptable envelope.
11. Persistence and replication do not make the estimate exact
AOF/RDB can persist HLL state and replicas can copy it, but durability protects the estimator state—not the identities you discarded. A backup of an HLL cannot reconstruct the original visitor list. Replication is asynchronous and is not a backup; later chapters cover those guarantees in depth.
13. Reproducible cleanup
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch11:visitors:exact atlasmart:ch11:visitors:hll atlasmart:ch11:hll:test atlasmart:ch11:hll:day1 atlasmart:ch11:hll:day2 atlasmart:ch11:hll:two-days
14. Production judgment
Use HLL when the product question is approximate distinct cardinality and fixed-ish memory is more valuable than recoverable membership. Measure observed relative error, memory, command latency, write rate, persistence traffic, replication lag, and merge topology. Keep HLL out of exact billing, security authorization, legal counts, or any workflow that needs deletion of individual observations. PFMERGE/multi-key PFCOUNT require Cluster locality planning; retries are naturally tolerant for duplicate PFADD inputs but cannot undo accidental additions.
15. Summary and next step
HyperLogLog trades identity and exactness for compact distinct-count estimation. Lesson 2 moves from “how many unique?” to “have I probably seen this item?” with Bloom filters—and introduces the first explicit false-positive budget.
Check your understanding
- What does PFADD returning 1 prove?
- Can HLL answer whether u42 was seen?
- What standard error does Redis document for HLL cardinality?
- Why is summing daily PFCOUNT values wrong for a two-day unique count?
- What does persistence preserve for an HLL?
Review the answers
At least one internal HLL register changed; it does not prove exact element novelty.
No. HLL does not retain membership identities.
Approximately 0.81% standard error.
The same visitor can appear on both days, so summing double-counts overlap; merge estimator states instead.
The estimator state, not the discarded original member list.
Authoritative references
- Redis probabilistic data types — current integrated probabilistic data-structure overview
- Redis data types — current Redis data-type surface
- HyperLogLog — cardinality-estimation model and operations
- PFADD — HyperLogLog insertion semantics
- PFCOUNT — standard error, memory, and union-count semantics
- PFMERGE — persistent HLL union/merge semantics
- Bloom filter — Bloom membership model and examples
- BF.RESERVE — capacity, false-positive rate, scaling, and memory formulas
- BF.INFO — Bloom capacity/filter/memory evidence
- Cuckoo filter — Cuckoo membership/deletion tradeoffs
- CF.DEL — safe deletion requirement and corruption warning
- CF.COUNT — Cuckoo multiplicity estimate semantics
- Count-Min Sketch — frequency-estimation model
- CMS.INITBYPROB — error/probability sizing controls
- CMS.MERGE — same-dimension merge and weights
- Top-K — HeavyKeepers-based heavy-hitter model
- TOPK.LIST — ranked top-k output and WITHCOUNT
- TOPK.COUNT — deprecated count command and undercount note
- t-digest — percentile/CDF model and merge operations
- TDIGEST.CREATE — compression versus memory/accuracy tradeoff
- TDIGEST.QUANTILE — quantile estimate semantics
- TDIGEST.INFO — observations, nodes, compression, memory evidence
- Probabilistic command compatibility — current command/Redis product compatibility matrix
- Redis 8.0 release notes — integrated probabilistic features and ACL-category change
- Redis 8.10 release notes — 8.10.1 security baseline for CMS/Top-K