Skip to content

Commit 526918f

Browse files
feat(core): RangeFilterExec — sorted-input per-partition range filter (purely additive) (#2262)
* feat(core): RangeFilterExec — sorted-input per-partition range filter (purely additive) Adds `RangeFilterExec`: filter that applies a per-input-partition half-open range predicate, widened by the operator's halo. Sibling of `PerPartitionFilterExec` (which handles arbitrary predicates); RFE specialises to `[lo, hi)` ranges over a `routing_expr` and gets a fast path for sorted inputs (binary-search slice + Arc-clone pass-through when a batch is entirely inside/outside the window). - Bounds are late-bound via `resolve_bounds`; wire encode refuses before resolution. Constructors: `try_new_pending`, `try_new_resolved`. - Halos + bounds use `ScalarValue` at the API + proto surface (generic over Arrow primitives); internal impl is Float64-only today and errors on non-Float64 until KLL widens support. - No in-tree callers — this is purely additive. - Includes serde roundtrip + fast/slow path unit tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(core): scope DataType import to tests, drop _touch_datatype DataType was only referenced textually in the test module (via `DataType::Float64` in schema builders); the non-test build treated the top-level import as unused, papered over by a `#[allow(dead_code)] fn _touch_datatype(_: DataType)`. Move the import into `mod tests` and remove the workaround. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(core): pub-export RangeBound + WidenedBound so RangeFilterExec signatures render as rustdoc links Both aliases were reachable only through structural spelling — `Vec<(Option<ScalarValue>, Option<ScalarValue>)>` for the raw form, `Vec<(Option<f64>, Option<f64>)>` for the widened form — because `range_filter` is a private module and neither alias was `pub`-re-exported. Rustdoc rendered `try_new_resolved` / `raw_bounds` / `widened_bounds` signatures with bare unlinkable names as a result. Bumping both to `pub` and re-exporting from `execution_plans` restores the signature → alias-page links. Addresses andygrove's review nits on #2262. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6610280 commit 526918f

5 files changed

Lines changed: 1341 additions & 3 deletions

File tree

ballista/core/proto/ballista.proto

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ message BallistaPhysicalPlanNode {
5858
PerPartitionFilterExecNode per_partition_filter = 10;
5959
PartitionedBoundedWindowAggExecNode partitioned_bounded_window_agg = 11;
6060
RangeShuffleReaderExecNode range_shuffle_reader = 12;
61+
RangeFilterExecNode range_filter = 13;
6162
}
6263
}
6364

@@ -135,6 +136,28 @@ message PerPartitionFilterExecNode {
135136
repeated datafusion.PhysicalExprNode predicates = 1;
136137
}
137138

139+
// Filter inputs with a per-input-partition half-open range predicate
140+
// widened by `halo_lo` / `halo_hi`. `raw_bounds[k]` is the cut range for
141+
// input partition `k` before halo widening; RFE widens internally at
142+
// resolve time. Zero halo recovers the exact range-repartition trim used
143+
// above `ShuffleReaderExec`; non-zero halo widens each partition's read
144+
// range to include a boundary "context" band (bounded RANGE-frame windows).
145+
// The child plan is plumbed by the framework as `inputs[0]` during decode.
146+
// Serialization requires bounds to be resolved.
147+
message RangeFilterExecNode {
148+
datafusion.PhysicalExprNode routing_expr = 1;
149+
datafusion_common.ScalarValue halo_lo = 2;
150+
datafusion_common.ScalarValue halo_hi = 3;
151+
repeated RangeBound raw_bounds = 4;
152+
}
153+
154+
// Half-open `[lo, hi)` cut range for one input partition. Either side may be
155+
// unset to signal ±∞.
156+
message RangeBound {
157+
datafusion_common.ScalarValue lo = 1;
158+
datafusion_common.ScalarValue hi = 2;
159+
}
160+
138161
// Wrapper for `BoundedWindowAggExec` that overrides
139162
// `required_input_distribution` to `Unspecified` — see the module doc on
140163
// `execution_plans::partitioned_bounded_window_agg` for what makes that safe.

ballista/core/src/execution_plans/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod ordered_range_repartition;
2626
mod partitioned_bounded_window_agg;
2727
mod per_partition_filter;
2828
pub mod plan_algebra;
29+
mod range_filter;
2930
mod range_repartition_common;
3031
mod range_shuffle_reader;
3132
mod runtime_stats;
@@ -47,6 +48,7 @@ pub use ordered_range_repartition::OrderedRangeRepartitionExec;
4748
pub use partitioned_bounded_window_agg::PartitionedBoundedWindowAggExec;
4849
pub use per_partition_filter::{PerPartitionFilterExec, range_partition_predicates};
4950
pub use plan_algebra::{preserves_distribution, preserves_partitioning};
51+
pub use range_filter::{RangeBound, RangeFilterExec, WidenedBound};
5052
pub use range_shuffle_reader::RangeShuffleReaderExec;
5153
pub use runtime_stats::{
5254
MergedRuntimeStats, RuntimeStatsExec, TaskRuntimeStats,

0 commit comments

Comments
 (0)