← All tutorials

07 / DATA STRUCTURES

Check membership.
Skip needless work.

Use CoolBox's EGH filter as a compact screen before an exact lookup. Insert integer IDs, measure false positives on unseen IDs, and learn when a filter is the right data structure.

10 MININTERMEDIATE

1. Understand “possibly present”

A probabilistic membership filter stores a compact hashed representation rather than an exact set of keys. CoolBox's EGH implementation hashes each value into several prime-sized boolean layers. Inserting sets one bucket in every layer; querying checks all corresponding buckets.

False means absent; true means possibly present. A positive can be caused by collisions with other keys. Confirm positives against an authoritative set or database. Inserted values should never return false while the filter remains intact, has not been cleared, and uses the same key representation.

This makes a filter useful for avoiding unnecessary database or cache reads. It is not suitable by itself for authorization, exact duplicate rejection, or deciding to discard data: a false positive could otherwise lose a legitimate item.

Conceptual EGH filter flow: a key hashes into multiple layers. An unset queried bucket means absent; all queried buckets set means possibly present and requires confirmation in an exact store.
Conceptual lookup diagram. Three shortened layers illustrate the mechanism; they are not the actual layer count, bucket sizes, or hash positions used by the example.

2. Size for the expected workload

Allocate for 1,000 expected insertions and a 0.01 target false-positive rate. Insert IDs 0 through 999, then query the disjoint range 100,000 through 109,999. Every positive in that second range is a known false positive.

The target is a sizing input, not a guaranteed measured rate. The occupancy-based estimate and the empirical rate on 10,000 probes answer different questions. Inserting far more keys than planned saturates the layers and increases false positives.

3. Insert and measure

Follow the matching installation guide. Use signed 64-bit integer keys for comparable examples across the bindings. The programs verify all inserted keys, count false positives on absent keys, report occupancy estimates, and clear the filter.

GO · EGH FILTER
package main

import (
    "fmt"
    "log"
    coolbox "github.com/MeanderingAI/CoolBox/_deliverables/libraries/bindings/go_bindings"
)

func run() error {
    filter, err := coolbox.NewInt64Filter(coolbox.EGHFilterKind, 1000, 0.01)
    if err != nil { return err }
    defer filter.Close()
    for id := int64(0); id < 1000; id++ {
        if err := filter.Insert(id); err != nil { return err }
    }
    for id := int64(0); id < 1000; id++ {
        present, err := filter.Contains(id)
        if err != nil { return err }
        if !present { return fmt.Errorf("false negative for %d", id) }
    }
    falsePositives := 0
    for id := int64(100000); id < 110000; id++ {
        present, err := filter.Contains(id)
        if err != nil { return err }
        if present { falsePositives++ }
    }
    estimated, err := filter.EstimatedFalsePositiveRate()
    if err != nil { return err }
    calls, err := filter.InsertCount()
    if err != nil { return err }
    approximate, err := filter.ApproximateCount()
    if err != nil { return err }
    fmt.Printf("Insert calls: %d; approximate count: %d\n", calls, approximate)
    fmt.Printf("False positives: %d/10000; empirical: %.4f; estimated: %.4f\n",
        falsePositives, float64(falsePositives)/10000, estimated)
    if err := filter.Clear(); err != nil { return err }
    present, err := filter.Contains(42)
    if err != nil { return err }
    if present { return fmt.Errorf("filter was not cleared") }
    return nil
}

func main() {
    if err := run(); err != nil { log.Fatal(err) }
}

4. Read the counters correctly

In the native C++ run of this exact example, all 1,000 inserted IDs were found, and 89 of 10,000 absent IDs returned positive: an empirical rate of 0.89%. The occupancy estimate rounded to 0.87%, and the approximate count was 1,000. Clearing the filter also passed its check. These are measured example results, not required outputs on every platform.

Measured results: 9,911 true negatives and 89 false positives among 10,000 absent probes. All 1,000 inserted IDs were found. Empirical false-positive rate 0.89 percent, rounded occupancy estimate 0.87 percent, sizing target 1 percent.
Results from the tutorial's native run. The stacked bar shows absent-probe outcomes; the lower chart uses an expanded rate scale. The occupancy estimate is rounded, and the 1% target is a sizing input rather than an observed result.

insert_count counts insertion calls, including duplicates. It is not exact distinct cardinality. approximate_count estimates cardinality from occupied buckets, while estimated_false_positive_rate multiplies layer occupancies; neither is a guarantee.

The empirical rate is false positives / 10,000 because all probe IDs are known absent. Verify zero false negatives separately on the inserted range. A measured rate will depend on the tested keys and implementation; do not require it to equal the configured 1% target exactly.

clear resets every layer and the insertion counter. This API does not expose per-item removal. Do not clear a bucket yourself: different keys can share it, so doing so could introduce false negatives.

5. Put an exact store behind it

On a negative query, skip an exact lookup only when the filter contains every authoritative key relevant to the request. On a positive query, consult the exact store. Keep updates ordered and synchronized; a stale filter can miss newly added records even though the filter algorithm itself has no false negatives for inserted keys.

Choose an exact hash set when you need exact membership and can afford storing keys. Choose an EGH or Bloom filter for compact negative screening. Compare memory and observed false positives under your real workload before choosing; this tutorial does not claim EGH is universally faster or smaller.

See the native EGH implementation for sizing and hashing details.