Skip to content

Commit d8f0dd1

Browse files
committed
more
1 parent 2e6d05c commit d8f0dd1

7 files changed

Lines changed: 168 additions & 55 deletions

File tree

vortex-array/src/arrays/filter/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub use vtable::FilterArray;
1010
mod execute;
1111

1212
mod kernel;
13+
mod parent_kernels;
1314
pub use kernel::FilterExecuteAdaptor;
1415
pub use kernel::FilterKernel;
1516
pub use kernel::FilterReduce;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Parent kernels for wrapper-side execution over [`Filter`].
5+
//!
6+
//! [`VariantGet`](crate::scalar_fn::fns::variant_get::VariantGet) relies on the underlying
7+
//! variant encoding to perform the real extraction work, so it cannot execute directly once a
8+
//! `Filter` wrapper sits between the expression and that encoding.
9+
//!
10+
//! This module handles that pass-through at the wrapper layer by filtering the wrapped variant
11+
//! child first and then re-dispatching `VariantGet` on the filtered child.
12+
13+
use vortex_error::VortexResult;
14+
15+
use crate::ArrayRef;
16+
use crate::ExecutionCtx;
17+
use crate::array::ArrayView;
18+
use crate::arrays::Filter;
19+
use crate::arrays::Variant;
20+
use crate::arrays::filter::FilterArrayExt;
21+
use crate::arrays::scalar_fn::ExactScalarFn;
22+
use crate::arrays::scalar_fn::ScalarFnArrayView;
23+
use crate::arrays::scalar_fn::ScalarFnFactoryExt;
24+
use crate::arrays::variant::VariantArrayExt;
25+
use crate::dtype::DType;
26+
use crate::kernel::ExecuteParentKernel;
27+
use crate::kernel::ParentKernelSet;
28+
use crate::scalar_fn::fns::variant_get::VariantGet;
29+
30+
pub(super) static PARENT_KERNELS: ParentKernelSet<Filter> =
31+
ParentKernelSet::new(&[ParentKernelSet::lift(&FilterVariantGetExecuteParent)]);
32+
33+
/// Pass `variant_get` through a `Filter` wrapper to the underlying variant child.
34+
#[derive(Debug)]
35+
struct FilterVariantGetExecuteParent;
36+
37+
impl ExecuteParentKernel<Filter> for FilterVariantGetExecuteParent {
38+
type Parent = ExactScalarFn<VariantGet>;
39+
40+
fn execute_parent(
41+
&self,
42+
array: ArrayView<'_, Filter>,
43+
parent: ScalarFnArrayView<'_, VariantGet>,
44+
child_idx: usize,
45+
ctx: &mut ExecutionCtx,
46+
) -> VortexResult<Option<ArrayRef>> {
47+
if child_idx != 0 {
48+
return Ok(None);
49+
}
50+
51+
let child = array.child();
52+
let inner = if let Some(variant) = child.as_opt::<Variant>() {
53+
variant.child().clone()
54+
} else if matches!(child.dtype(), DType::Variant(_)) {
55+
child.clone()
56+
} else {
57+
return Ok(None);
58+
};
59+
60+
let filtered = inner
61+
.filter(array.filter_mask().clone())?
62+
.execute::<ArrayRef>(ctx)?;
63+
64+
VariantGet
65+
.try_new_array(parent.len(), parent.options.clone(), [filtered])?
66+
.execute::<ArrayRef>(ctx)
67+
.map(Some)
68+
}
69+
}

vortex-array/src/arrays/filter/vtable.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::arrays::filter::array::FilterData;
3232
use crate::arrays::filter::array::SLOT_NAMES;
3333
use crate::arrays::filter::execute::execute_filter;
3434
use crate::arrays::filter::execute::execute_filter_fast_paths;
35+
use crate::arrays::filter::parent_kernels::PARENT_KERNELS;
3536
use crate::arrays::filter::rules::PARENT_RULES;
3637
use crate::arrays::filter::rules::RULES;
3738
use crate::buffer::BufferHandle;
@@ -170,6 +171,15 @@ impl VTable for Filter {
170171
PARENT_RULES.evaluate(array, parent, child_idx)
171172
}
172173

174+
fn execute_parent(
175+
array: ArrayView<'_, Self>,
176+
parent: &ArrayRef,
177+
child_idx: usize,
178+
ctx: &mut ExecutionCtx,
179+
) -> VortexResult<Option<ArrayRef>> {
180+
PARENT_KERNELS.execute(array, parent, child_idx, ctx)
181+
}
182+
173183
fn reduce(array: ArrayView<'_, Self>) -> VortexResult<Option<ArrayRef>> {
174184
RULES.evaluate(array)
175185
}

vortex-array/src/arrays/slice/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! [`ArrayParentReduceRule`] and [`ExecuteParentKernel`] respectively.
1010
1111
mod array;
12+
mod parent_kernels;
1213
mod rules;
1314
mod slice_;
1415
mod vtable;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
//! Parent kernels for wrapper-side execution over [`Slice`].
5+
//!
6+
//! Most scalar functions can commute with `Slice` via generic scalar-fn rules, but
7+
//! [`VariantGet`](crate::scalar_fn::fns::variant_get::VariantGet) is unusual: it has to reach the
8+
//! underlying variant encoding's `execute_parent` kernel rather than executing directly.
9+
//!
10+
//! This module keeps that wrapper-specific pass-through on the wrapper side. When a
11+
//! `VariantGet` parent sits directly above a `Slice`, we slice the wrapped variant child first and
12+
//! then re-dispatch `VariantGet` on the sliced child so execution can continue at the underlying
13+
//! variant encoding.
14+
15+
use vortex_error::VortexResult;
16+
17+
use crate::ArrayRef;
18+
use crate::ExecutionCtx;
19+
use crate::array::ArrayView;
20+
use crate::arrays::Slice;
21+
use crate::arrays::Variant;
22+
use crate::arrays::scalar_fn::ExactScalarFn;
23+
use crate::arrays::scalar_fn::ScalarFnArrayView;
24+
use crate::arrays::scalar_fn::ScalarFnFactoryExt;
25+
use crate::arrays::slice::SliceArrayExt;
26+
use crate::arrays::variant::VariantArrayExt;
27+
use crate::dtype::DType;
28+
use crate::kernel::ExecuteParentKernel;
29+
use crate::kernel::ParentKernelSet;
30+
use crate::scalar_fn::fns::variant_get::VariantGet;
31+
32+
pub(super) static PARENT_KERNELS: ParentKernelSet<Slice> =
33+
ParentKernelSet::new(&[ParentKernelSet::lift(&SliceVariantGetExecuteParent)]);
34+
35+
/// Pass `variant_get` through a `Slice` wrapper to the underlying variant child.
36+
#[derive(Debug)]
37+
struct SliceVariantGetExecuteParent;
38+
39+
impl ExecuteParentKernel<Slice> for SliceVariantGetExecuteParent {
40+
type Parent = ExactScalarFn<VariantGet>;
41+
42+
fn execute_parent(
43+
&self,
44+
array: ArrayView<'_, Slice>,
45+
parent: ScalarFnArrayView<'_, VariantGet>,
46+
child_idx: usize,
47+
ctx: &mut ExecutionCtx,
48+
) -> VortexResult<Option<ArrayRef>> {
49+
if child_idx != 0 {
50+
return Ok(None);
51+
}
52+
53+
let child = array.child();
54+
let inner = if let Some(variant) = child.as_opt::<Variant>() {
55+
variant.child().clone()
56+
} else if matches!(child.dtype(), DType::Variant(_)) {
57+
child.clone()
58+
} else {
59+
return Ok(None);
60+
};
61+
62+
let sliced = inner
63+
.slice(array.slice_range().clone())?
64+
.execute::<ArrayRef>(ctx)?;
65+
66+
VariantGet
67+
.try_new_array(parent.len(), parent.options.clone(), [sliced])?
68+
.execute::<ArrayRef>(ctx)
69+
.map(Some)
70+
}
71+
}

vortex-array/src/arrays/slice/vtable.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::arrays::slice::SliceArrayExt;
3030
use crate::arrays::slice::array::CHILD_SLOT;
3131
use crate::arrays::slice::array::SLOT_NAMES;
3232
use crate::arrays::slice::array::SliceData;
33+
use crate::arrays::slice::parent_kernels::PARENT_KERNELS;
3334
use crate::arrays::slice::rules::PARENT_RULES;
3435
use crate::buffer::BufferHandle;
3536
use crate::dtype::DType;
@@ -158,6 +159,15 @@ impl VTable for Slice {
158159
) -> VortexResult<Option<ArrayRef>> {
159160
PARENT_RULES.evaluate(array, parent, child_idx)
160161
}
162+
163+
fn execute_parent(
164+
array: ArrayView<'_, Self>,
165+
parent: &ArrayRef,
166+
child_idx: usize,
167+
ctx: &mut ExecutionCtx,
168+
) -> VortexResult<Option<ArrayRef>> {
169+
PARENT_KERNELS.execute(array, parent, child_idx, ctx)
170+
}
161171
}
162172
impl OperationsVTable<Slice> for Slice {
163173
fn scalar_at(

vortex-array/src/scalar_fn/fns/variant_get/mod.rs

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ use vortex_session::VortexSession;
1414

1515
use crate::ArrayRef;
1616
use crate::ExecutionCtx;
17-
use crate::arrays::Filter;
18-
use crate::arrays::Slice;
1917
use crate::arrays::Variant;
20-
use crate::arrays::filter::FilterArrayExt;
21-
use crate::arrays::scalar_fn::ScalarFnFactoryExt;
22-
use crate::arrays::slice::SliceArrayExt;
2318
use crate::arrays::variant::VariantArrayExt;
2419
use crate::dtype::DType;
2520
use crate::dtype::Nullability;
@@ -46,8 +41,11 @@ pub use path::VariantPathElement;
4641
/// requested path may not exist in every row.
4742
///
4843
/// Execution is handled by variant encodings (e.g. `ParquetVariantArray`) via `execute_parent`.
49-
/// The canonical `VariantArray` does not support direct execution; a `reduce` rule unwraps
50-
/// the `VariantArray` wrapper to expose the underlying encoding.
44+
/// The canonical `VariantArray` does not support direct execution, so `VariantGet` keeps a small
45+
/// `reduce` rule that unwraps a direct `VariantArray` child to expose the underlying encoding.
46+
/// Wrapper arrays such as `Slice` and `Filter` forward `VariantGet` from their own
47+
/// `execute_parent` hooks so the expression can still reach the underlying variant encoding
48+
/// without teaching `VariantGet` about wrapper-specific array shapes.
5149
#[derive(Clone)]
5250
pub struct VariantGet;
5351

@@ -222,12 +220,7 @@ impl ScalarFnVTable for VariantGet {
222220
args: &dyn ExecutionArgs,
223221
ctx: &mut ExecutionCtx,
224222
) -> VortexResult<ArrayRef> {
225-
let input = args.get(0)?;
226-
227-
if let Some(rewritten) = rewrite_wrapped_variant_input(input, options, ctx)? {
228-
return Ok(rewritten);
229-
}
230-
223+
let _ = (options, args, ctx);
231224
vortex_bail!("variant_get cannot be executed directly")
232225
}
233226

@@ -262,48 +255,6 @@ impl ScalarFnVTable for VariantGet {
262255
}
263256
}
264257

265-
fn rewrite_wrapped_variant_input(
266-
input: ArrayRef,
267-
options: &VariantGetOptions,
268-
ctx: &mut ExecutionCtx,
269-
) -> VortexResult<Option<ArrayRef>> {
270-
if let Some(slice) = input.as_opt::<Slice>() {
271-
let Some(inner) = unwrap_variant_input(slice.child()) else {
272-
return Ok(None);
273-
};
274-
let sliced = inner
275-
.slice(slice.slice_range().clone())?
276-
.execute::<ArrayRef>(ctx)?;
277-
return VariantGet
278-
.try_new_array(input.len(), options.clone(), [sliced])?
279-
.execute::<ArrayRef>(ctx)
280-
.map(Some);
281-
}
282-
283-
if let Some(filter) = input.as_opt::<Filter>() {
284-
let Some(inner) = unwrap_variant_input(filter.child()) else {
285-
return Ok(None);
286-
};
287-
let filtered = inner
288-
.filter(filter.filter_mask().clone())?
289-
.execute::<ArrayRef>(ctx)?;
290-
return VariantGet
291-
.try_new_array(input.len(), options.clone(), [filtered])?
292-
.execute::<ArrayRef>(ctx)
293-
.map(Some);
294-
}
295-
296-
Ok(None)
297-
}
298-
299-
fn unwrap_variant_input(input: &ArrayRef) -> Option<ArrayRef> {
300-
if let Some(variant) = input.as_opt::<Variant>() {
301-
return Some(variant.child().clone());
302-
}
303-
304-
matches!(input.dtype(), DType::Variant(_)).then(|| input.clone())
305-
}
306-
307258
#[cfg(test)]
308259
mod tests {
309260
use vortex_session::VortexSession;

0 commit comments

Comments
 (0)