Skip to content

perf: add a streaming contains join to engine v2 - #778

Merged
azimafroozeh merged 2 commits into
ModernRelay:mainfrom
azimafroozeh:issue-775-cross-binding-predicate-product
Sep 27, 2026
Merged

azimafroozeh merged 2 commits into
ModernRelay:mainfrom
azimafroozeh:issue-775-cross-binding-predicate-product

Conversation

@azimafroozeh

Copy link
Copy Markdown
Collaborator

What & why

Addresses the cross-binding filter failure in engine v2. Previously, the query built a Cartesian product before filtering $p.text contains $m.number, which could exhaust the query-memory limit.

  • Place cross-binding predicates at their join, before traversal.
  • Use Aho-Corasick matching for eligible text contains joins and discard nonmatching passages as the right scan streams.

Recorded debug-CLI measurements on local storage: median of three warm runs and maximum warm process RSS. All workloads have 266 Matter nodes and 2,000 SourceRevision nodes. Base 24da4f54 and the streaming implementation were measured in separate rounds.

Passages Text per passage Passages matching Base time Streaming time Speedup
20,000 512 B 0.2% 5.97 s 0.10 s ≈60×
20,000 256 B 0.2% 5.92 s 0.10 s ≈59×
208,000 64 B 0.2% 62.50 s 0.15 s ≈417×
208,000 512 B 0.2% Memory refusal 0.20 s N/A
34,000 512 B 100% 10.20 s 0.15 s ≈68×
208,000 64 B 100% 64.17 s 0.54 s ≈119×

Speedup is base time divided by streaming time, rounded to a whole multiple. The memory-refusal case has no successful baseline to divide by. The last workload was re-measured on the final tree at 0.53 s and 130 MiB peak RSS, with the same 30 rows.

Backing issue / RFC

Checklist

  • Change is focused (cross-binding predicate execution in engine v2).
  • Tests added/updated (result semantics, plan placement, runtime counters, memory limits, plan replay, a generated differential against the plain filtered join).
  • Public docs complete (execution and explain docs, release note).
  • Invariants satisfied (the pair buffer's scratch is charged before it grows; a replayed plan whose scan marker and join disagree refuses).

Local verification

  • cargo check --workspace --tests -q --message-format=short: passed.
  • cargo test -p omnigraph-gqt --locked -q: 380 passed.
  • cargo test -p omnigraph-planner: 75 passed.
  • cargo test -p omnigraph-engine --lib engine::: 74 passed; engine_v2 11, engine_v2_memory 23, engine_v2_plan_replay 13, literal_filters 14.
  • cargo clippy --workspace --all-targets -q --message-format=short -- -D warnings -W clippy::dbg_macro: passed.
  • cargo fmt --all --check: passed.
  • cargo test --workspace --exclude omnigraph-gqt --exclude omnigraph-dst --locked --no-fail-fast --features omnigraph-engine/failpoints,omnigraph-cluster/failpoints: 3,402 passed, 4 failed, 29 ignored. The four failures come from local environment restrictions (three CLI session-lock tests and one Unix-socket test) and fail the same way without this change.
  • Vocabulary guard: the openapi surface passes; the rust-string surface fails with 1,075 entries, all reported while evaluating the merge base, none from this change.

Notes for reviewers

  • Applies to set engine = v2; engine v1 retains the reported overflow behavior.
  • A ContainsJoin forms only when the text binding's scan is on the join's right: written second, or moved there when both row counts are known and the needles are no more than the texts. Otherwise the conjunct runs on a filtered CrossJoin, bounded in memory but testing every pair.
  • A limit above the join waits for one output batch of kept pairs (the batch size or its byte budget) rather than the first right batch.
  • A pipelined scan reads bounded Lance batches with a readahead of 2, so at most one decoded batch sits outside the pool's count. On the 208,000-passage workload this measured no slower than Lance's default readahead.
  • Explain output gains ContainsJoin, CrossJoin.filters and the scan's runtime_filter, advancing EXPLAIN_VERSION to 3. Passage text is still read from storage; no text index is added.

@azimafroozeh
azimafroozeh added this pull request to the merge queue Sep 27, 2026
Merged via the queue into ModernRelay:main with commit 737aa74 Sep 27, 2026
31 checks passed
@azimafroozeh
azimafroozeh deleted the issue-775-cross-binding-predicate-product branch September 27, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant