SysDesignPrep.com
Interactive concepts

HyperLogLog explained: an interactive distinct-count simulator

HyperLogLog counts how many distinct items a stream contains, such as unique visitors, unique search queries or unique IPs, using a fixed, tiny amount of memory: 12 KB counts a billion distinct items to within about 1%. It cannot list the items or say whether one was seen; it only estimates how many there were. Two sketches can be merged into one that counts their union.

The playground feeds numbered visitors into a sketch. Change the number of registers and visitors, repeat visitors, or merge two days, and compare the estimate with the truth.

RegistersDistinct visitors

1,000,000 distinct visitors in 16,384 registers, 12 KB. The estimate is 1,002,474, +0.2% from the truth; the typical error at this size is ±0.81%, and it stays about the same from a thousand visitors to a billion. Storing every visitor ID exactly would take at least 8 MB.

The first 512 of 16,384 registers: longest run of zeros seen, plus one
register 0: 6register 1: 8register 2: 8register 3: 8register 4: 5register 5: 9register 6: 5register 7: 8register 8: 8register 9: 6register 10: 7register 11: 9register 12: 7register 13: 5register 14: 6register 15: 5register 16: 9register 17: 10register 18: 6register 19: 6register 20: 5register 21: 7register 22: 7register 23: 6register 24: 6register 25: 5register 26: 4register 27: 6register 28: 7register 29: 7register 30: 7register 31: 6register 32: 12register 33: 5register 34: 7register 35: 7register 36: 8register 37: 9register 38: 6register 39: 6register 40: 11register 41: 6register 42: 8register 43: 5register 44: 11register 45: 7register 46: 5register 47: 8register 48: 6register 49: 10register 50: 8register 51: 9register 52: 6register 53: 7register 54: 4register 55: 14register 56: 6register 57: 7register 58: 5register 59: 5register 60: 7register 61: 5register 62: 5register 63: 8register 64: 9register 65: 10register 66: 6register 67: 8register 68: 6register 69: 5register 70: 10register 71: 6register 72: 10register 73: 7register 74: 5register 75: 4register 76: 7register 77: 6register 78: 7register 79: 10register 80: 6register 81: 6register 82: 7register 83: 8register 84: 7register 85: 10register 86: 7register 87: 6register 88: 6register 89: 6register 90: 7register 91: 7register 92: 8register 93: 8register 94: 6register 95: 8register 96: 6register 97: 8register 98: 8register 99: 7register 100: 8register 101: 7register 102: 6register 103: 7register 104: 10register 105: 5register 106: 8register 107: 8register 108: 6register 109: 6register 110: 5register 111: 7register 112: 11register 113: 5register 114: 5register 115: 8register 116: 8register 117: 10register 118: 7register 119: 8register 120: 7register 121: 11register 122: 6register 123: 7register 124: 8register 125: 7register 126: 6register 127: 8register 128: 6register 129: 10register 130: 13register 131: 8register 132: 5register 133: 6register 134: 9register 135: 7register 136: 8register 137: 8register 138: 9register 139: 8register 140: 7register 141: 7register 142: 9register 143: 6register 144: 6register 145: 6register 146: 8register 147: 6register 148: 4register 149: 7register 150: 5register 151: 9register 152: 8register 153: 8register 154: 9register 155: 6register 156: 6register 157: 11register 158: 9register 159: 5register 160: 9register 161: 5register 162: 12register 163: 7register 164: 7register 165: 8register 166: 10register 167: 8register 168: 9register 169: 7register 170: 10register 171: 7register 172: 6register 173: 8register 174: 10register 175: 7register 176: 7register 177: 7register 178: 11register 179: 8register 180: 8register 181: 4register 182: 8register 183: 5register 184: 6register 185: 7register 186: 7register 187: 5register 188: 7register 189: 6register 190: 7register 191: 8register 192: 9register 193: 6register 194: 6register 195: 12register 196: 7register 197: 6register 198: 7register 199: 6register 200: 6register 201: 7register 202: 7register 203: 9register 204: 10register 205: 8register 206: 7register 207: 7register 208: 7register 209: 5register 210: 11register 211: 11register 212: 5register 213: 7register 214: 5register 215: 8register 216: 10register 217: 7register 218: 8register 219: 14register 220: 7register 221: 7register 222: 8register 223: 5register 224: 5register 225: 5register 226: 6register 227: 6register 228: 7register 229: 9register 230: 8register 231: 5register 232: 5register 233: 8register 234: 8register 235: 7register 236: 4register 237: 6register 238: 8register 239: 8register 240: 8register 241: 6register 242: 8register 243: 7register 244: 7register 245: 6register 246: 10register 247: 9register 248: 8register 249: 10register 250: 6register 251: 6register 252: 8register 253: 7register 254: 8register 255: 6register 256: 9register 257: 6register 258: 7register 259: 5register 260: 5register 261: 5register 262: 7register 263: 4register 264: 7register 265: 7register 266: 9register 267: 6register 268: 12register 269: 8register 270: 9register 271: 10register 272: 8register 273: 6register 274: 7register 275: 6register 276: 9register 277: 8register 278: 10register 279: 9register 280: 7register 281: 6register 282: 12register 283: 9register 284: 8register 285: 7register 286: 7register 287: 9register 288: 6register 289: 12register 290: 5register 291: 7register 292: 6register 293: 5register 294: 7register 295: 5register 296: 11register 297: 6register 298: 7register 299: 8register 300: 9register 301: 7register 302: 5register 303: 12register 304: 5register 305: 7register 306: 6register 307: 5register 308: 7register 309: 6register 310: 8register 311: 5register 312: 7register 313: 7register 314: 6register 315: 8register 316: 9register 317: 6register 318: 6register 319: 7register 320: 10register 321: 6register 322: 11register 323: 10register 324: 8register 325: 10register 326: 8register 327: 7register 328: 9register 329: 7register 330: 6register 331: 10register 332: 8register 333: 7register 334: 8register 335: 6register 336: 8register 337: 6register 338: 8register 339: 6register 340: 6register 341: 6register 342: 7register 343: 6register 344: 7register 345: 7register 346: 7register 347: 5register 348: 8register 349: 10register 350: 6register 351: 4register 352: 9register 353: 6register 354: 7register 355: 11register 356: 9register 357: 9register 358: 6register 359: 10register 360: 8register 361: 6register 362: 7register 363: 7register 364: 11register 365: 8register 366: 6register 367: 5register 368: 9register 369: 7register 370: 8register 371: 7register 372: 6register 373: 6register 374: 5register 375: 7register 376: 10register 377: 7register 378: 6register 379: 6register 380: 12register 381: 6register 382: 10register 383: 10register 384: 6register 385: 7register 386: 6register 387: 6register 388: 7register 389: 10register 390: 5register 391: 7register 392: 7register 393: 11register 394: 8register 395: 6register 396: 6register 397: 10register 398: 6register 399: 7register 400: 6register 401: 7register 402: 8register 403: 6register 404: 9register 405: 7register 406: 6register 407: 7register 408: 7register 409: 10register 410: 5register 411: 5register 412: 8register 413: 9register 414: 7register 415: 6register 416: 7register 417: 10register 418: 8register 419: 6register 420: 6register 421: 9register 422: 9register 423: 5register 424: 5register 425: 7register 426: 7register 427: 7register 428: 5register 429: 10register 430: 6register 431: 8register 432: 8register 433: 7register 434: 5register 435: 8register 436: 7register 437: 7register 438: 9register 439: 7register 440: 6register 441: 11register 442: 7register 443: 4register 444: 8register 445: 7register 446: 11register 447: 6register 448: 9register 449: 8register 450: 5register 451: 10register 452: 6register 453: 6register 454: 7register 455: 9register 456: 7register 457: 10register 458: 6register 459: 6register 460: 9register 461: 7register 462: 7register 463: 9register 464: 6register 465: 10register 466: 8register 467: 6register 468: 9register 469: 8register 470: 6register 471: 7register 472: 7register 473: 18register 474: 5register 475: 7register 476: 7register 477: 9register 478: 6register 479: 4register 480: 7register 481: 10register 482: 10register 483: 7register 484: 10register 485: 8register 486: 5register 487: 7register 488: 5register 489: 11register 490: 5register 491: 7register 492: 7register 493: 11register 494: 5register 495: 5register 496: 7register 497: 5register 498: 8register 499: 8register 500: 7register 501: 6register 502: 8register 503: 7register 504: 8register 505: 5register 506: 8register 507: 5register 508: 8register 509: 7register 510: 8register 511: 6
Error of the estimate as visitors are added
−3.3%0+3.3%101k1Mdistinct visitors so far
True distinct1,000,000visitors
Estimate1,002,474+0.2% from the truth
Sketch size12 KB16,384 registers of 6 bits
Exact set8 MB8 bytes per ID, at the very least
±1.04/√m, the typical errorthis sketch’s error

How HyperLogLog works

  1. Hash each item to a random-looking number. The same item always gives the same hash, so repeats change nothing.
  2. Pick a register with the first p bits of the hash; there are m = 2p registers.
  3. Count leading zeros in the rest of the hash, and keep the largest count seen, plus one, in that register.
  4. Estimate: a run of k zeros turns up about once in 2k items, so each register guesses the count; the harmonic mean of all the guesses, scaled by m, is the estimate. For small counts, when many registers are still empty, counting the empty ones is more accurate, and the sketch switches to that.

One register alone would be a wild guess, like estimating how many coins were flipped from the longest run of heads. Many registers, each seeing a different slice of the items, average the luck out.

Accuracy and memory

The standard error is about 1.04/√m, and it does not depend on the count. Each register needs only 6 bits, since runs longer than 63 zeros never happen, so memory is tiny and fixed:

RegistersMemoryTypical error
1612 bytes±26%
256192 bytes±6.5%
1,024768 bytes±3.3%
4,0963 KB±1.6%
16,38412 KB±0.81%

In the playground, 16,384 registers estimate a million visitors as 1,002,474, 0.25% off, where an exact set of 64-bit IDs would need at least 8 MB. With 16 registers the same million comes out as 707,765, 29% low. The bump in the error curve at about two and a half times the number of registers is where the estimator switches from counting empty registers to the main formula, a known bias that the HyperLogLog++ variant corrects.

Merging sketches

Two sketches with the same number of registers merge by keeping the larger value in each register, and the result is exactly the sketch you would have built from both streams together. That is what makes HyperLogLog useful at scale: count per server, per shard, per hour or per day, then merge for any combination, without ever storing or shipping the raw IDs. Adding counts would double-count people who appear in both; merging does not. The one thing sketches cannot do well is subtract or intersect: estimates of overlaps computed by inclusion and exclusion are noisy.

HyperLogLog in Redis

# one sketch per page per day; each is at most 12 KB
PFADD visitors:2026-10-23:/pricing user:81 user:4410 user:81   # repeats change nothing
PFCOUNT visitors:2026-10-23:/pricing                           # distinct visitors, ~0.81% error

# weekly uniques without double counting people who came back
PFMERGE visitors:week43:/pricing visitors:2026-10-19:/pricing visitors:2026-10-20:/pricing ...
PFCOUNT visitors:week43:/pricing

Redis uses 16,384 registers, a sparse encoding for small counts and a 12 KB dense one above that. BigQuery, Snowflake, Presto and Postgres extensions offer approximate distinct counts built on the same algorithm, often the HyperLogLog++ variant from Google, which corrects the estimate’s bias at small and medium counts.

In a system design interview

When asked for unique counts at scale, say why exact is not worth it: “Unique viewers per video per day would need a set of user IDs per video, gigabytes a day. We keep a HyperLogLog per video per day in Redis, 12 KB each, with under 1% error, and merge days for weekly and monthly uniques.” Expect the follow-ups: whether 1% error is acceptable for the product (billing usually needs exact counts), how to count uniques across shards, and what to do for frequency questions, where a count-min sketch fits instead.

Read the guide to probabilistic data structures, try Bloom filters, which answer “have I seen this?” instead of “how many?”, or watch a strong candidate design an ad click aggregator.

Questions people ask

What is HyperLogLog?

A probabilistic data structure that estimates how many distinct items are in a stream or set, using a small fixed amount of memory. It hashes each item, uses part of the hash to choose a register, and records in that register the longest run of leading zeros seen; together the registers estimate the count, typically within about 1% using 12 KB.

How accurate is HyperLogLog?

Its standard error is about 1.04 divided by the square root of the number of registers, regardless of how many items are counted. With 16,384 registers, as in Redis, that is about 0.81%: a true count of a million usually comes out within 8,000 or so. Fewer registers use less memory and give larger errors.

How much memory does HyperLogLog use?

A fixed amount set by the number of registers, each needing 6 bits. 16,384 registers take 12 KB whether the stream has a thousand or a billion distinct items. An exact set of a billion 64-bit IDs would need at least 8 GB. Implementations also use a sparse encoding while the count is small.

Can HyperLogLog sketches be merged?

Yes. Two sketches with the same number of registers merge by taking the larger value in each register, which gives exactly the sketch of the combined stream. That lets you count uniques per shard, server or day and combine them for any union, counting someone who appears in both only once.

What is the difference between HyperLogLog and a Bloom filter?

A Bloom filter answers whether an item has been seen, with possible false positives, and grows with the number of items. HyperLogLog answers how many distinct items there were, in fixed memory, but cannot answer whether a particular item was seen. They are often used together: one for membership, one for cardinality.

How do you count unique visitors at scale?

Keep a HyperLogLog per page or product per time bucket, for example per day, add each visitor ID to it, and read the estimate. Merge daily sketches for weekly and monthly uniques. Redis provides PFADD, PFCOUNT and PFMERGE, and analytics databases provide approximate distinct-count functions built on HyperLogLog.

When should you not use HyperLogLog?

When the count must be exact, such as for billing or financial reporting; when you need to know which items were seen, or how often each was seen, which a count-min sketch or exact counters answer; and when you need intersections of sets, which HyperLogLog can only estimate with large errors.