Chris Collins

Tools · distributed

Probabilistic data structures

Bloom, counting Bloom and cuckoo filters, the Count-Min sketch with conservative update and heavy hitters, HyperLogLog (original, HLL++ sparse and Ertl's estimator), the t-digest and reservoir sampling — each fed by a live seeded stream, drawn from the inside, with accuracy-vs-memory charts against the formulas.

Added

Works with

How to use it

Six structures that trade a little accuracy for a lot of memory, each running live in the page: pick a tab, press Play, and watch keys stream in while the bits, buckets, counters, registers, centroids or samples change — next to the exact answer and the theory. Every stream is seeded, so Reset replays the same run; the accuracy-vs-memory charts run in a Web Worker.

How to use it

Each tab has the same parts: the structure’s settings, a Live panel (▶ Play / ⏸ Pause, +1, +100, ↺ Reset, and the stream speed in items per second), a chart of accuracy against memory measured over many seeded runs, and the formulas. ⛶ Full screen (or the F key; Esc leaves) shows just the live view of the open tab, filling the window; the tabs keep working in it.

  • Bloom — m bits, k hash functions, design capacity n. Shows bits per key, the best k = (m/n)·ln 2, the false-positive rate (FPR) at n and with the best k, and the memory. Live inserts k0, k1, k2…: the bit array lights up (orange rings are bits just set), with the fill, the theoretical FPR, the FPR from the fill (fillᵏ) and the FPR measured on 2,000 keys never added. Type a key to Add, Check (probed bits outlined green when set, red when 0; a "maybe" for a key never added is called out as a false positive) or Delete. Tick Counting Bloom filter for counters of 1–8 bits that allow deletes; counters that saturate are drawn red and can never be decremented again. Charts: FPR as the filter fills (theory and measured), and FPR against bits per key from 2 to 20.

  • Cuckoo — buckets, entries per bucket b, fingerprint bits f and the kick limit. Live inserts keys until an insert fails; every bucket is drawn with its fingerprints in hex, the new key’s two candidate buckets dashed, and the moves of the last insert numbered and listed ("kick out 0x3a → its other bucket 17"). Load α, bits per key f/α, the FPR bound and the measured FPR. Chart: bits per key against FPR for cuckoo filters filled to failure with 4- to 20-bit fingerprints, against the Bloom filter’s 1.44·log₂(1/ε) and the log₂(1/ε) minimum.

  • Count-Min — width w, depth d, heavy hitters to keep, and whether to draw the conservative-update sketch (both run side by side). The stream is Zipf(s), uniform or all-distinct over a number of keys, with a seed. The counter grid is drawn as a heat map; Estimate a key to see its d counters outlined and the minimum taken. Shows ε = e/w, δ = e^−d, the εN bound, the mean overestimate for both update rules and the share of keys over εN (it should be at most δ), and a top-k table of true counts against both estimates. Chart: overestimate against width (log–log) with the bound.

  • HyperLogLog — precision p (16 to 65,536 registers), the estimator shown big, and HLL sparse mode. The registers are drawn as bars (or as a histogram of their values when there are too many); the live panel compares the estimate with the exact distinct count, the standard error 1.04/√m and the memory against an exact set, and a table shows the raw harmonic-mean estimate, linear counting, Flajolet et al.'s switch, HLL's thresholds and Ertl’s estimator. Charts: this run’s error as the count grows (with the ±1.04/√m band), RMSE against the number of registers, and the bias of each estimator against cardinality — the bump where linear counting hands over to the raw estimate.

  • t-digest — compression δ and a value distribution (log-normal latency, exponential, normal, Pareto, bimodal "cache hit / miss", uniform). Centroids are drawn along the quantile axis: width is a centroid’s share of the data, height its count — tiny at the tails. A table compares p0.1, p1, p25, p50, p90, p99 and p99.9 with the exact values (value and rank error). Chart: rank error at seven quantiles for δ = 20 to 500.

  • Reservoir — sample size k, stream length N and the algorithm drawn. The slots flash as items replace their occupants; Algorithm R and Algorithm L run side by side so you can compare how many random numbers each draws. Chart: how often each stream position ends up in the sample over 20,000 seeded runs, against k/N, with a χ² statistic.

What it implements, and the sources

  • Hashing: MurmurHash3 x86_32 (checked against the SMHasher reference outputs); two values make a 64-bit hash. Bloom and Count-Min positions use Kirsch–Mitzenmacher double hashing, gᵢ = h₁ + i·h₂ mod m — A. Kirsch and M. Mitzenmacher, "Less Hashing, Same Performance: Building a Better Bloom Filter" (ESA 2006).

  • Bloom filter: B. H. Bloom, "Space/Time Trade-offs in Hash Coding with Allowable Errors" (CACM 1970). The classic FPR formula is slightly optimistic for small m — P. Bose et al., "On the false-positive rate of Bloom filters" (IPL 2008). Counting Bloom filters and the overflow bound m·(e·ln 2/i)^i: L. Fan, P. Cao, J. Almeida and A. Broder, "Summary Cache" (IEEE/ACM ToN 2000).

  • Cuckoo filter: B. Fan, D. G. Andersen, M. Kaminsky and M. Mitzenmacher, "Cuckoo Filter: Practically Better Than Bloom" (CoNEXT 2014) — partial-key cuckoo hashing, 500 kicks, a victim slot, ε ≤ 2b/2^f, and maximum loads of about 50%, 84%, 95% and 98% for b = 1, 2, 4, 8.

  • Count-Min sketch: G. Cormode and S. Muthukrishnan, "An Improved Data Stream Summary: The Count-Min Sketch and its Applications" (J. Algorithms 2005). Conservative update: C. Estan and

    1. Varghese, "New Directions in Traffic Measurement and Accounting" (SIGCOMM 2002).

  • HyperLogLog: P. Flajolet, É. Fusy, O. Gandouet and F. Meunier, "HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm" (AofA 2007). HLL++: S. Heule, M. Nunkesser and

    1. Hall, "HyperLogLog in Practice" (EDBT 2013) — the sparse representation at p′ = 25 and the linear-counting thresholds are implemented; the empirical bias-correction tables are not (the bias bump shows why they exist). Improved estimator: O. Ertl, "New cardinality estimation algorithms for HyperLogLog sketches" (arXiv:1702.01284, 2017). Redis’s PFADD/PFCOUNT use 16,384 6-bit registers (12 KB, 0.81%) — try them in the Redis tool.

  • t-digest: T. Dunning and O. Ertl, "Computing Extremely Accurate Quantiles Using t-Digests" (arXiv:1902.04023, 2019) — the merging variant with the k₁ scale function.

  • Reservoir sampling: J. S. Vitter, "Random Sampling with a Reservoir" (ACM TOMS 1985), Algorithm R; K.-H. Li, "Reservoir-Sampling Algorithms of Time Complexity O(n(1 + log(N/n)))" (ACM TOMS 1994), Algorithm L.

The tests check the hash against reference vectors, Bloom FPR against theory over 100,000 probes, cuckoo loads and FPR bounds, the Count-Min guarantee (never under, at most δ of keys over εN), HyperLogLog RMSE within 3σ of 1.04/√m and near-exact sparse counts, t-digest rank error at the tails, and reservoir uniformity with a χ² test — all with fixed seeds.

Limits

  • Streams are synthetic (Zipf, uniform or distinct ids as strings k0, k1…); nothing reads your data. Sizes are capped so the page stays responsive: Bloom filters to 2 million bits in the page, HyperLogLog to p = 16, Zipf universes to a million keys.

  • HLL here has no bias-correction tables, and sparse entries are counted at 4 bytes each rather than HLL's varint-delta encoding; the memory shown is the ideal 6 bits per register.

  • The t-digest is the merging variant with k₁ only (no k₂/k₃ scale functions, no AVL-tree variant); quantiles interpolate between centroid centres as in the paper.

  • Measured false-positive rates come from a few thousand probes, so small rates are noisy in the live view; the sweep charts use 20,000–40,000 probes.

Related: probability (a quick Bloom calculator), cache simulator (W-TinyLFU admits with a Count-Min sketch), storage engines (an LSM tree’s per-SSTable Bloom filters), Redis (PFADD, PFCOUNT, PFMERGE), hashes, statistics, latency numbers.

Linking to an example

Share link copies a URL with every setting. Hand-written links work too; add the tab after #: bloom, cuckoo, cms, hll, tdigest or reservoir. For example ?m=10000&k=7&n=1000#bloom or ?p=14&est=ffgm#hll.

Parameter Meaning Example

m, k, n

Bloom: bits, hash functions, design capacity

m=9586&k=7&n=1000

counting, cbits

Bloom: counting filter on, bits per counter (1–8)

counting=true&cbits=4

buckets, b, f, kicks

Cuckoo: buckets (power of two), entries per bucket (1, 2, 4, 8), fingerprint bits, max kicks

buckets=64&b=4&f=12

w, d, conservative, topk

Count-Min: width, depth, draw conservative update, heavy hitters kept

w=272&d=5

p, est, sparse

HyperLogLog: precision 4–16, estimator ertl, ffgm or hllpp, start sparse

p=14&est=ertl

delta, tdist, tn

t-digest: compression, values (lognormal, exponential, normal, pareto, bimodal, uniform), values per Fill

delta=50&tdist=pareto

size, rn, alg

Reservoir: sample size, stream length, R or L

size=10&rn=10000&alg=L

dist, s, universe, seed

The stream (Count-Min, HyperLogLog): zipf, uniform or distinct; Zipf exponent; distinct keys; seed

dist=zipf&s=1.2

example

One of the presets below; parameters written beside it override the preset’s

example=hll-redis

Presets (?example=…; each opens on its tab):

example= Shows

bloom-1pct

1% false positives for 1,000 keys: 9,586 bits, k = 7 (open)

bloom-10-bits

10 bits a key, k = 7: 0.82% predicted (open)

bloom-overfull

256 bits, 3 hashes, 150 keys: the filter says "maybe" to almost everything (open)

counting-overflow

2-bit counters saturate and deletes stop clearing them (open)

cuckoo-95

b = 4, 8-bit fingerprints: fills to about 95%; FPR ≤ 3.1% (open)

cuckoo-b1

One slot per bucket: inserts fail near 50% load (open)

cms-paper

ε = 1% (w = 272), δ ≈ 0.7% (d = 5) on a Zipf 1.1 stream (open)

cms-conservative

A narrow sketch on a flatter stream, with conservative update (open)

hll-redis

Redis’s HyperLogLog: 16,384 registers, 0.81%, 12 KB (open)

hll-tiny

16 registers with the original estimator: ±26% (open)

hll-sparse

HLL++ sparse mode on all-distinct keys, then dense (open)

tdigest-latency

Log-normal latencies, δ = 100: p99 and p99.9 from about 60 centroids (open)

tdigest-pareto

A heavy-tailed Pareto stream with δ = 30 (open)

reservoir-l

Algorithm L: 10 from 10,000 with about 100 random numbers (open)

Runs entirely in your browser; nothing you type leaves this page.