SD System Design In Depth
0%
lesson system-designprobabilistic-structures

HyperLogLog cardinality estimation

Module 4.3: Probabilistic Sketches & Stream Analytics Updated Sep 17, 2026
📄 Cheat Sheet
Hyperloglog and Cardinality Estimation
Arpit Bhayani Hyperloglog and Cardinality Estimation Watch on YouTube ↗

Recent, engineer-focused explanation of registers, leading-zero ranks, harmonic mean and the memory versus error trade-off.

0:00 / --:--

HyperLogLog for Unique Counting

Counting the exact number of unique visitors (cardinality) over a month requires storing every single user ID in a Set. At Facebook or Google scale, this demands Terabytes of memory just to track unique counts.

The Magic of HyperLogLog (HLL)

HyperLogLog is a probabilistic data structure that estimates cardinality with extreme memory efficiency. Instead of storing IDs, it hashes the ID and looks at the binary representation of the hash. It tracks the maximum number of leading zeros seen in any hash. If you see a hash with 10 leading zeros, that hints you have processed on the order of 2^10 unique items. A single such observation is a very noisy estimate (one lucky hash can be off by orders of magnitude), so the real algorithm splits hashes across many registers and averages them, as described below.

Memory vs Accuracy Trade-off

Standard HLL uses one well-distributed hash per identity. The first p bits select one of m = 2^p registers; the remaining bits supply a rank based on the first set bit. Each register retains its maximum observed rank, and the estimator combines all registers with bias corrections. More registers use more memory and reduce standard error. Redis's implementation uses about 12 KB in its dense representation and targets roughly 0.81% standard error, but serialized format and sparse behavior are implementation-specific.

If you don't need exact accounting (e.g., displaying "1.2M Unique Views" on a dashboard), HLL is the perfect tool, replacing Terabytes of RAM with Kilobytes.

PFADD unique_visitors_today "user_123"
PFCOUNT unique_visitors_today // Returns estimated count

Worked example: precision vs memory

Precision pRegisters m = 2 to the power pMemory at 6 bits per registerStandard error, 1.04 divided by sqrt m1 sigma at 100 million uniques
101,024768 bytes3.25 percentplus or minus 3.25 million
124,0963 KB1.63 percentplus or minus 1.63 million
14, Redis default16,38412 KB0.81 percentplus or minus 812,000
1665,53648 KB0.41 percentplus or minus 406,000

Compare exact counting: 100 million 8-byte user IDs in a hash set is at least 800 MB, and several GB with typical hash table overhead, per metric per day. HLL at 12 KB is roughly five orders of magnitude smaller.

Walking one item through

With p = 14, hash "user_123" to 64 bits. The first 14 bits, say 00000101101001, select register 361. In the remaining 50 bits, the first 1 appears at position 4, so the rank is 4. If register 361 currently holds 2, it becomes 4; if it holds 6, it stays 6. Re-adding "user_123" produces the same hash and changes nothing, which is why HLL naturally ignores duplicates.

Practical refinements

  • Small-range correction: when many registers are still zero, the estimator switches to linear counting, which is far more accurate for small cardinalities.
  • HyperLogLog++ (Google, 2013): 64-bit hashes, empirical bias correction, and a sparse representation for small sets. Redis similarly uses a sparse encoding until the set grows.
  • Where it is used: Redis PFADD and PFCOUNT, BigQuery APPROX_COUNT_DISTINCT and HLL_COUNT functions, Presto and Trino approx_distinct, Druid and Pinot HLL aggregators.

Common interview uses

QuestionWhy HLL fits
Daily active users per countryOne 12 KB sketch per country per day; merge for weekly or monthly
Unique visitors per pageMillions of pages x 12 KB can still be large; use lower precision or sparse encoding for small pages
Distinct IPs hitting an endpoint, for abuse detectionFixed memory per endpoint regardless of attack size
Distinct search queries per dayAccurate to about 1 percent without storing queries

When the interviewer asks for exact counts, switch to a keyed set in a database or a batch COUNT DISTINCT; when they ask for intersections, mention Theta sketches.

Check yourself Question 1 of 3
Why duplicates are free recall
From: Walking one item through

The same user ID is added to a HyperLogLog one million times. Why does the estimate not grow?

HyperLogLog Estimator
O(1) Memory
Actual Count:
0
HLL Estimate:
0
Error:
0%

Key Takeaways

Exact cardinality counting requires linear memory (O(N)).
HyperLogLog uses a fixed register array whose size is selected from the required error; Redis's dense representation is about 12 KB.
Use HLL when a small error rate (~1%) is acceptable for unique counting.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue