Expand description
LPG (Labeled Property Graph) planner.
Converts logical plans with LPG operators (NodeScan, Expand, etc.) to physical operators that execute against an LPG store.
§Structure
Logical operators are consumed by plan_operator, dispatched to
per-operator submodules that share the crate-private Planner
struct:
| Submodule | Owns |
|---|---|
scan | plan_node_scan: label, property, and index-seek scans |
expand | single-hop and multi-hop expansion (factorized chain) |
filter | predicate rewriting, zone maps, index pushdown, EXISTS/COUNT |
expression | LogicalExpression -> FilterExpression conversion |
join | hash, nested-loop, leapfrog, multi-way, semi/anti |
aggregate, project, mutation | the rest of the pipeline |
§Rewrites applied during planning
The planner is not a pure tree walker: it performs several shape transforms up-front because they decide which physical operator is legal, not just which is faster. Each rewrite lives in the submodule that owns the corresponding logical operator.
-
Factorized expand chains (
expand::plan_expand_chain): two or more consecutiveExpands are collapsed into a singleLazyFactorizedChainOperator. A hand-rolled tree ofExpandoperators would materialise the Cartesian product between hops (O(d^k) rows for a k-hop query with average degree d); factorisation represents each hop as a set per row and evaluates upward filters lazily, which is asymptotically better and preserves filter semantics (filters apply to the flattened view). Disabled whenfactorized_executionis false on the planner, used as an escape hatch for operators that need materialised intermediate state. -
EXISTS / NOT EXISTS as semi/anti joins (
filter::extract_complex_exists): anything more than a trivial single-hop EXISTS is rewritten to a semi-join (EXISTS) or anti-join (NOT EXISTS) before the filter is planned. A literal nested re-execution would re-scan the subquery per outer row; the join form piggy-backs on the regular hash-join infrastructure. The fast path inexpression::convert_expressionkeeps trivial single-hop EXISTS as inline predicates so small queries stay scan-local. -
EXISTS inside OR (
filter::extract_exists_from_or): semi-joins filter rows and therefore compose incorrectly with the disjunctive scalar side of an OR. The rewrite splits the OR into a semi-join branch and a regular filter branch, UNIONNs them, and deduplicates. Without the split, rows satisfied only by the scalar side would be dropped. -
COUNT subquery comparisons (
filter::extract_count_comparison):COUNT { ... } op Nrewrites into Apply + Aggregate + Filter. Evaluating the COUNT inline per row would be a correlated subquery; Apply + Aggregate reuses the hash-aggregate physical operator.
§Filter pushdown and index selection
filter::plan_filter is the central point. It tries a sequence of
optimisations before falling back to a generic FilterOperator; the
ordering is load-bearing:
- Complex EXISTS / OR / COUNT rewrites (above). These must run first because later steps assume a pure-scalar predicate.
- Zone-map short-circuit: if the column’s zone summary proves the
predicate cannot match any row group, plan an
EmptyOperator. - Property index seek: equality on an indexed property becomes an index scan (O(1) per lookup) instead of a filtered full scan.
- Range index lookup:
>,<,>=,<=on an indexed property becomes a range scan. - Hybrid vector+text pushdown (feature-gated): compound
AND/OR predicates over
vector_match/text_matchare folded into a single fused scan. - Generic
FilterOperator: the residual predicate wraps the input scan.
Whatever remains after a pushdown (e.g. the non-index-backed half of an AND) is planned as a residual filter on top of the chosen scan, so the returned tree is always semantically equivalent to the input plan.
§Transaction context
Every operator inherits the planner’s viewing_epoch and
transaction_id. Factorised chains and mutations carry them
through with_transaction_context() so MVCC visibility is applied
at every hop: see crate::transaction for the epoch/visibility
rules.
Structs§
- Planner
- Converts a logical plan to a physical operator tree for LPG stores.