Skip to content

feat(table): optional prefix bloom filters for prefix-scan pruning#2305

Open
shaunpatterson wants to merge 1 commit into
dgraph-io:mainfrom
shaunpatterson:feat/prefix-bloom
Open

feat(table): optional prefix bloom filters for prefix-scan pruning#2305
shaunpatterson wants to merge 1 commit into
dgraph-io:mainfrom
shaunpatterson:feat/prefix-bloom

Conversation

@shaunpatterson

Copy link
Copy Markdown
Contributor

Motivation

The per-table bloom filter is built over the full user key and is only consulted for single-key iteration (prefixIsKey). A real prefix scan over many distinct keys sharing a prefix gets no bloom benefit — only key-range pruning. Prefix scans are a common access pattern (all keys under a predicate/namespace).

What changed

New opt-in WithBloomPrefixLength(n) (default 0 = disabled). When n > 0, each SSTable additionally stores a bloom filter built over the first n bytes of every user key. A prefix-bounded scan then consults it (Table.DoesNotHavePrefix) in pickTable/pickTables to skip whole SSTables that provably contain no key with the scan prefix — pruning tables whose key range straddles the prefix where range-pruning alone can't help.

Stored as two appended TableIndex flatbuffer fields (bloom_prefix_filter, bloom_prefix_length).

Compatibility & correctness

DoesNotHavePrefix is conservative: it returns "do not skip" unless the table has a prefix bloom and the scan prefix is at least prefixBloomLength bytes and the bloom proves absence. Keys shorter than n are hashed whole (they can't match a longer scan prefix anyway). Tables written without a prefix bloom (old format, or n == 0) are never skipped. Default (BloomPrefixLength == 0) behavior is byte-for-byte unchanged.

Testing

go build, go vet, go test . ./table/... green. Tests cover: present prefix returns all matches; absent prefix pruned (incl. a table whose key range straddles the absent prefix); short scan prefix conservatively not pruned; old-format table opens and is never skipped; default-off unchanged.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NtGkC4K2J2XYwcAKwjhHbM

Add WithBloomPrefixLength(n) option. When n>0, the table builder hashes the
n-byte prefix of each user key into a SEPARATE bloom filter, stored in two new
FlatBuffers TableIndex fields (bloom_prefix_filter, bloom_prefix_length)
appended at the end of the schema. Appending is forward/backward compatible:
old readers ignore the new fields and old tables decode them as nil/0.

Prefix-bounded iterators (opt.Prefix set, not single-key) consult the prefix
bloom via Table.DoesNotHavePrefix in pickTable/pickTables to skip whole SSTables
that provably contain no key with the scan prefix. Tables without a prefix bloom
always return false, preserving existing behavior. Default (n=0) is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NtGkC4K2J2XYwcAKwjhHbM
@shaunpatterson shaunpatterson requested a review from a team as a code owner June 22, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant