Skip to content

Commit 0de2c09

Browse files
committed
Bind abstract aggregate stats to legacy counts
Signed-off-by: "Nicholas Gates" <nick@nickgates.com>
1 parent fe12e71 commit 0de2c09

5 files changed

Lines changed: 59 additions & 12 deletions

File tree

vortex-array/src/expr/pruning/pruning_expr.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ mod tests {
229229
use crate::expr::pruning::field_path_stat_field_name;
230230
use crate::expr::root;
231231
use crate::expr::stats::Stat;
232-
use crate::scalar::Scalar;
233232
use crate::scalar_fn::fns::between::BetweenOptions;
234233
use crate::scalar_fn::fns::between::StrictComparison;
235234
use crate::stats::session::StatsSession;
@@ -591,7 +590,7 @@ mod tests {
591590
&HashMap::from_iter([
592591
(
593592
FieldPath::from_name("float_col"),
594-
HashSet::from_iter([Stat::Max])
593+
HashSet::from_iter([Stat::Max, Stat::NaNCount])
595594
),
596595
(
597596
FieldPath::from_name("int_col"),
@@ -603,7 +602,7 @@ mod tests {
603602
&converted,
604603
&or(
605604
and(
606-
lit(Scalar::null(DType::Bool(Nullability::Nullable))),
605+
eq(col("float_col_nan_count"), lit(0u64)),
607606
lt_eq(col("float_col_max"), lit(10f32)),
608607
),
609608
gt_eq(col("int_col_min"), lit(10)),

vortex-array/src/scalar_fn/fns/is_not_null.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ mod tests {
118118
use crate::expr::eq;
119119
use crate::expr::get_item;
120120
use crate::expr::is_not_null;
121-
use crate::expr::lit;
122121
use crate::expr::or;
123122
use crate::expr::pruning::checked_pruning_expr;
124123
use crate::expr::root;
@@ -266,7 +265,7 @@ mod tests {
266265
&pruning_expr,
267266
&or(
268267
eq(col("a_null_count"), RowCount.new_expr(EmptyOptions, [])),
269-
lit(Scalar::null(DType::Bool(Nullability::Nullable))),
268+
eq(col("a_null_count"), RowCount.new_expr(EmptyOptions, [])),
270269
)
271270
);
272271
assert_eq!(

vortex-array/src/scalar_fn/fns/is_null.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ mod tests {
251251
&pruning_expr,
252252
&or(
253253
eq(col("a_null_count"), lit(0u64)),
254-
lit(Scalar::null(DType::Bool(Nullability::Nullable))),
254+
eq(col("a_null_count"), lit(0u64)),
255255
)
256256
);
257257
assert_eq!(

vortex-array/src/stats/bind.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,22 @@
1111
use vortex_error::VortexResult;
1212

1313
use crate::aggregate_fn::AggregateFnRef;
14+
use crate::aggregate_fn::fns::all_nan::AllNan;
15+
use crate::aggregate_fn::fns::all_non_nan::AllNonNan;
16+
use crate::aggregate_fn::fns::all_non_null::AllNonNull;
17+
use crate::aggregate_fn::fns::all_null::AllNull;
1418
use crate::dtype::DType;
1519
use crate::expr::Expression;
20+
use crate::expr::eq;
1621
use crate::expr::lit;
1722
use crate::expr::stats::Stat;
1823
use crate::expr::traversal::NodeExt;
1924
use crate::expr::traversal::Transformed;
2025
use crate::scalar::Scalar;
26+
use crate::scalar_fn::EmptyOptions;
27+
use crate::scalar_fn::ScalarFnVTableExt;
2128
use crate::scalar_fn::fns::stat::StatFn;
29+
use crate::scalar_fn::internal::row_count::RowCount;
2230

2331
/// A target that can bind abstract statistics to concrete expressions.
2432
pub trait StatBinder {
@@ -56,12 +64,53 @@ pub trait StatBinder {
5664
aggregate_fn: &AggregateFnRef,
5765
stat_dtype: &DType,
5866
) -> VortexResult<Option<Expression>> {
67+
if aggregate_fn.is::<AllNan>() {
68+
let Some(nan_count) = self.bind_legacy_stat(input, Stat::NaNCount)? else {
69+
return Ok(None);
70+
};
71+
return Ok(Some(eq(nan_count, RowCount.new_expr(EmptyOptions, []))));
72+
}
73+
74+
if aggregate_fn.is::<AllNonNan>() {
75+
let Some(nan_count) = self.bind_legacy_stat(input, Stat::NaNCount)? else {
76+
return Ok(None);
77+
};
78+
return Ok(Some(eq(nan_count, lit(0u64))));
79+
}
80+
81+
if aggregate_fn.is::<AllNull>() {
82+
let Some(null_count) = self.bind_legacy_stat(input, Stat::NullCount)? else {
83+
return Ok(None);
84+
};
85+
return Ok(Some(eq(null_count, RowCount.new_expr(EmptyOptions, []))));
86+
}
87+
88+
if aggregate_fn.is::<AllNonNull>() {
89+
let Some(null_count) = self.bind_legacy_stat(input, Stat::NullCount)? else {
90+
return Ok(None);
91+
};
92+
return Ok(Some(eq(null_count, lit(0u64))));
93+
}
94+
5995
let Some(stat) = Stat::from_aggregate_fn(aggregate_fn) else {
6096
return Ok(None);
6197
};
6298
self.bind_stat(input, stat, stat_dtype)
6399
}
64100

101+
/// Bind one of the legacy stat slots for `input`.
102+
fn bind_legacy_stat(
103+
&mut self,
104+
input: &Expression,
105+
stat: Stat,
106+
) -> VortexResult<Option<Expression>> {
107+
let input_dtype = input.return_dtype(self.scope())?;
108+
let Some(stat_dtype) = stat.dtype(&input_dtype) else {
109+
return Ok(None);
110+
};
111+
self.bind_stat(input, stat, &stat_dtype)
112+
}
113+
65114
/// Expression to use when a stat is unavailable.
66115
///
67116
/// The default is a nullable null literal, which preserves three-valued

vortex-layout/src/layouts/zoned/zone_map.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ mod tests {
346346
}
347347

348348
#[test]
349-
fn all_null_stat_fn_lowers_to_unknown_mask() {
349+
fn all_null_stat_fn_uses_null_count() {
350350
let zone_map = ZoneMap::try_new(
351351
PType::U64.into(),
352352
StructArray::from_fields(&[(
@@ -363,12 +363,12 @@ mod tests {
363363
let mask = zone_map.prune(&all_null(root()), &SESSION).unwrap();
364364
assert_arrays_eq!(
365365
mask.into_array(),
366-
BoolArray::from_iter([false, false, false])
366+
BoolArray::from_iter([false, true, true])
367367
);
368368
}
369369

370370
#[test]
371-
fn all_non_null_stat_fn_lowers_to_unknown_mask() {
371+
fn all_non_null_stat_fn_uses_null_count() {
372372
let zone_map = ZoneMap::try_new(
373373
PType::U64.into(),
374374
StructArray::from_fields(&[(
@@ -385,7 +385,7 @@ mod tests {
385385
let mask = zone_map.prune(&all_non_null(root()), &SESSION).unwrap();
386386
assert_arrays_eq!(
387387
mask.into_array(),
388-
BoolArray::from_iter([false, false, false])
388+
BoolArray::from_iter([true, false, false])
389389
);
390390
}
391391

@@ -485,7 +485,7 @@ mod tests {
485485
let mask = zone_map.prune(&pruning_expr, &SESSION).unwrap();
486486
assert_arrays_eq!(
487487
mask.into_array(),
488-
BoolArray::from_iter([false, false, false])
488+
BoolArray::from_iter([true, false, false])
489489
);
490490
}
491491

@@ -527,7 +527,7 @@ mod tests {
527527
let pruning_expr = falsify(&expr, PType::F32.into());
528528

529529
let mask = zone_map.prune(&pruning_expr, &SESSION).unwrap();
530-
assert_arrays_eq!(mask.into_array(), BoolArray::from_iter([false, false]));
530+
assert_arrays_eq!(mask.into_array(), BoolArray::from_iter([false, true]));
531531
}
532532

533533
#[test]

0 commit comments

Comments
 (0)