Theta Sketch

Estimates cardinality like HyperLogLog, but also supports exact set operations (union, intersection, difference) directly between two sketches, without ever bringing the original sets back into memory.

How it works

Every item is hashed to a pseudo-uniform value in [0, 1). The sketch retains the k smallest hashes it has ever seen, below a shrinking threshold θ (theta) that starts at 1. Once more than k distinct hashes have been admitted, the largest retained hash is evicted and θ shrinks to that evicted value: this is the "KMV" (K-Minimum-Values) or "bottom-k" sketch technique.

Since hashes are uniformly distributed over [0, 1), the retained set is really a uniform random sample of all distinct items restricted to the region below θ. That gives an unbiased cardinality estimator: estimate = |retained| / θ. Long runs of small hashes below a tiny θ imply a huge number of distinct items were needed to produce them, exactly the same style of reasoning HyperLogLog uses with leading-zero runs instead.

The key extra trick: because the retained set is just "the k smallest hashes below θ", two sketches can be combined by taking the smaller of their two thetas, restricting both retained sets to that shared region, and then doing ordinary set union/intersection/ difference on the (small) retained hash sets. No decompression back to the original items is ever needed: this is what Apache DataSketches and systems like Apache Druid use for "how many distinct users matched filter A and filter B" queries over huge datasets.

Interactive demo

Sketch A

0.0θ = 1.0000 · retained = 01.0
True |A|0
Estimate0.0

Sketch B

0.0θ = 1.0000 · retained = 01.0
True |B|0
Estimate0.0
0.0θ = 1.0000 · retained = 01.0
Exact result0
Sketch estimate0.0
Abs. error0.0
Retained (result)0
No operations yet. Try adding an item above.

API surface

OperationDescriptionComplexity
new ThetaSketch(k)Allocate a sketch retaining up to k hashes, θ starts at 1.O(k) space
update(item): ThetaStepHash item; admit it if below θ, evicting the max hash (shrinking θ) once over k entries.O(k) time
estimate(): numberUnbiased cardinality estimate: |retained| / θ.O(k) time
union(other): ThetaSketchCombine retained sets restricted to the smaller θ, re-trimming to k if needed.O(k log k) time
intersect(other): ThetaSketchHashes retained by both sketches, restricted to the smaller θ.O(k) time
difference(other): ThetaSketch"A-not-B": hashes retained by this sketch but not the other.O(k) time