perf: predicate push-down for Expr clauses + mixed rule optimization (#207, #206)#249
Merged
Merged
Conversation
…le optimization) Covers issues #207 and #206: extends optimizer::plan() to accept Expr clauses and interleave them at the earliest position where their variables are bound, and routes the StratifiedEvaluator mixed-rules path through the updated planner. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d rules) TDD plan covering optimizer.rs, matcher.rs, executor.rs, evaluator.rs, and a new Criterion benchmark. 9 tasks, each with exact file paths, code blocks, and expected test output. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…positioning Adds expr_vars() and pattern_bound_vars() helpers. plan() now accepts Vec<WhereClause> (Pattern + Expr) and returns Vec<(WhereClause, Option<IndexHint>)>. Each Expr is inserted at the earliest position after all its variables are bound by preceding patterns. No-variable Exprs and Exprs with unbound variables are appended at the end. Closes part of #207. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ution pub(crate) method used by the executor and evaluator plan loops added in #207: applies an index hint for the first pattern (unit seed) and falls back to hash-join for subsequent patterns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task B refactored plan() to accept Vec<WhereClause> and return Vec<(WhereClause, Option<IndexHint>)>, but executor.rs wasn't updated. Extract pattern clauses with their hints to unblock Task C testing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…query_with_rules() Replaces the two-phase pattern-match-then-expr-filter with a single ordered loop in both query execution paths. Pattern clauses expand bindings via match_with_hint_seeded(); Expr clauses filter/extend inline at their push-down position. Removes both top-level apply_expr_clauses post-passes. Not/NotJoin/Or/OrJoin handling is unchanged. Also suppresses dead-code on match_patterns_with_hints and get_patterns (retained for future use), fixes collapsible_if and indexing_slicing warnings introduced by the new code in optimizer.rs and matcher.rs. Closes part of #207. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use the Binding type alias instead of spelling out the full HashMap type in the inline plan loops. Fix the evaluate_branch doc comment which incorrectly stated it mirrored the top-level execute_query order (the top-level now uses an interleaved push-down loop). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…down StratifiedEvaluator mixed-rules loop now collects Pattern + Expr clauses and calls optimizer::plan(), processing them in the same ordered loop as the executor. Expr clauses are pushed down to the earliest valid position in the rule body. Not/NotJoin filtering is unchanged. Closes #206. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ing it Replace unwrap_or_default() with ? so storage read failures surface as errors rather than silently producing an empty candidate set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Measures multi-pattern query with a selective [(> ?v N)] predicate at 1K/10K/100K fact scales. Threshold set at 90th percentile (10% pass rate). Provides baseline for evaluating push-down gains. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
adityamukho
added a commit
that referenced
this pull request
May 17, 2026
Wave 2 (PRs #249, #251, #253) was missing from CHANGELOG.md, ROADMAP.md, and TEST_COVERAGE.md: - CHANGELOG.md: add Wave 2 section between Wave 3 and Wave 1 entries - ROADMAP.md: add Wave 2 to timeline between Wave 1 and Wave 3 - TEST_COVERAGE.md: add Wave 2 completion status note (no new tests — all optimizer + benchmark work covered by existing 850 tests) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This was referenced May 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
optimizer::plan()to acceptVec<WhereClause>(Pattern + Expr) and return an interleaved plan. EachExprpredicate clause is positioned at the earliest point where all its variables are bound by preceding patterns, rather than being applied as a post-pass over the full binding set.StratifiedEvaluatormixed-rules path through the updatedplan(), giving mixed rules both selectivity-based pattern ordering and Expr push-down with no separate implementation.Changes
src/query/datalog/optimizer.rsexpr_vars()helper — recursively collects?foovariable names from anExprtreepattern_bound_vars()helper — collects variables bound by aPattern's EAV slotsplan()signature changed:Vec<Pattern> → Vec<(Pattern, IndexHint)>becomesVec<WhereClause> → Vec<(WhereClause, Option<IndexHint>)>Expris inserted atpos + 1after the last pattern that completes its variable setsrc/query/datalog/matcher.rspub(crate) match_with_hint_seeded()— uses the index hint for the first pattern (unit seed), falls back to hash-join for subsequent patterns; used by the executor/evaluator plan loopssrc/query/datalog/executor.rsexecute_query()andexecute_query_with_rules(): replaced two-phase match-then-filter with a single ordered loop processingPattern(join) andExpr(filter/extend) clauses in plan orderapply_expr_clausespost-passesNot/NotJoin/Or/OrJoinhandling is unchangedsrc/query/datalog/evaluator.rsStratifiedEvaluatormixed-rules loop now routes throughplan()instead of bypassing it, gaining both pattern selectivity ordering and Expr push-downbenches/minigraf_bench.rsquery/predicate_pushdownbenchmark group (1K/10K/100K scales, 90th-percentile threshold → ~10% pass rate)Test plan
cargo test— all 598+ tests passcargo clippy -- -D warnings— no warningscargo bench --bench minigraf_bench -- query/predicate_pushdown— benchmark runs without panicFollow-up
🤖 Generated with Claude Code