Skip to content

Commit 65241c2

Browse files
Add plan optimizer rules and push expressions (#9196)
## Summary - add typed `PlanParentReduceRule` and type-erased adapter APIs for child-driven physical-plan rewrites - add an ordered static `PlanParentRuleSet` whose first successful rewrite wins - register concrete `Eval` reductions for `Concat`, `Take`, `RowIdx`, and `Pack` Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
1 parent 36c61fa commit 65241c2

11 files changed

Lines changed: 1603 additions & 77 deletions

File tree

vortex-layout/src/plan/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod children;
1111
mod display;
1212
mod lower;
1313
mod optimize;
14+
pub mod optimizer;
1415
mod plans;
1516
mod typed;
1617
mod vtable;
@@ -38,12 +39,13 @@ pub use plans::PackPlan;
3839
pub use plans::RowIdx;
3940
pub use plans::RowIdxData;
4041
pub use plans::RowIdxPlan;
41-
pub use plans::RowIdxPlanMetadata;
4242
pub use plans::SegmentScan;
4343
pub use plans::SegmentScanData;
4444
pub use plans::SegmentScanPlan;
4545
pub use plans::Take;
4646
pub use plans::TakePlan;
47+
pub use plans::plan_row_idx_expression;
48+
pub use plans::row_idx_dtype;
4749
pub use typed::DynPlan;
4850
pub use typed::Plan;
4951
pub use typed::PlanParts;

vortex-layout/src/plan/optimize.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
//! Generic bottom-up optimization over physical plans.
4+
//! Plan optimization.
5+
//!
6+
//! The optimizer applies static rewrites top-down, optimizes children, then retries rewrites
7+
//! exposed by the optimized children.
58
69
use vortex_error::VortexResult;
710

8-
use crate::plan::Eval;
911
use crate::plan::PlanRef;
12+
use crate::plan::optimizer::reduce_parent;
13+
use crate::plan::optimizer::reduce_plan;
14+
15+
fn reduce(plan: &PlanRef) -> VortexResult<Option<PlanRef>> {
16+
if let Some(rewritten) = reduce_plan(plan)? {
17+
return Ok(Some(rewritten));
18+
}
19+
for child_idx in 0..plan.child_count() {
20+
if let Some(rewritten) = reduce_parent(plan, child_idx)? {
21+
return Ok(Some(rewritten));
22+
}
23+
}
24+
Ok(None)
25+
}
1026

1127
/// Optimizes `plan`, preserving its dtype and row domain.
1228
pub fn optimize(plan: PlanRef) -> VortexResult<PlanRef> {
29+
if let Some(rewritten) = reduce(&plan)? {
30+
return optimize(rewritten);
31+
}
32+
1333
let mut children = Vec::with_capacity(plan.child_count());
1434
let mut changed = false;
1535
for child in plan.children().iter() {
@@ -19,17 +39,13 @@ pub fn optimize(plan: PlanRef) -> VortexResult<PlanRef> {
1939
children.push(optimized);
2040
}
2141

22-
let plan = if changed {
23-
plan.with_children(children)?
24-
} else {
25-
plan
26-
};
27-
28-
let Some(eval) = plan.as_opt::<Eval>() else {
42+
if !changed {
2943
return Ok(plan);
30-
};
31-
if eval.expression().is_root() {
32-
return eval.child_plan();
44+
}
45+
46+
let plan = plan.with_children(children)?;
47+
if let Some(rewritten) = reduce(&plan)? {
48+
return optimize(rewritten);
3349
}
3450
Ok(plan)
3551
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Static rewrite rules for physical plans.
5+
6+
mod rules;
7+
8+
pub use rules::DynPlanParentReduceRule;
9+
pub use rules::DynPlanReduceRule;
10+
pub use rules::PlanParentReduceRule;
11+
pub use rules::PlanParentReduceRuleAdapter;
12+
pub use rules::PlanParentRuleSet;
13+
pub use rules::PlanReduceRule;
14+
pub use rules::PlanReduceRuleAdapter;
15+
pub use rules::PlanRuleSet;
16+
use vortex_error::VortexResult;
17+
18+
use super::Concat;
19+
use super::Eval;
20+
use super::Pack;
21+
use super::PlanRef;
22+
use super::Take;
23+
use super::plans::EvalIdentityRule;
24+
use super::plans::ExpressionConcatRule;
25+
use super::plans::ExpressionPackRule;
26+
use super::plans::ExpressionTakeRule;
27+
28+
static EVAL_IDENTITY_RULE: PlanReduceRuleAdapter<Eval, EvalIdentityRule> =
29+
PlanReduceRuleAdapter::new(EvalIdentityRule);
30+
31+
static PLAN_RULES: PlanRuleSet = PlanRuleSet::new(&[&EVAL_IDENTITY_RULE]);
32+
33+
static EXPRESSION_CONCAT_RULE: PlanParentReduceRuleAdapter<Concat, ExpressionConcatRule> =
34+
PlanParentReduceRuleAdapter::new(ExpressionConcatRule);
35+
static EXPRESSION_TAKE_RULE: PlanParentReduceRuleAdapter<Take, ExpressionTakeRule> =
36+
PlanParentReduceRuleAdapter::new(ExpressionTakeRule);
37+
static EXPRESSION_PACK_RULE: PlanParentReduceRuleAdapter<Pack, ExpressionPackRule> =
38+
PlanParentReduceRuleAdapter::new(ExpressionPackRule);
39+
40+
static PARENT_RULES: PlanParentRuleSet = PlanParentRuleSet::new(&[
41+
&EXPRESSION_CONCAT_RULE,
42+
&EXPRESSION_TAKE_RULE,
43+
&EXPRESSION_PACK_RULE,
44+
]);
45+
46+
/// Attempts a static rewrite for `plan`.
47+
pub(crate) fn reduce_plan(plan: &PlanRef) -> VortexResult<Option<PlanRef>> {
48+
PLAN_RULES.evaluate(plan)
49+
}
50+
51+
/// Attempts a static rewrite for `parent` and its child at `child_idx`.
52+
pub(crate) fn reduce_parent(parent: &PlanRef, child_idx: usize) -> VortexResult<Option<PlanRef>> {
53+
let Some(child) = parent.child(child_idx)? else {
54+
return Ok(None);
55+
};
56+
PARENT_RULES.evaluate(&child, parent, child_idx)
57+
}

0 commit comments

Comments
 (0)