Skip to content

Commit 824cee7

Browse files
authored
Compare timestamp parts without evaluating each comparison twice (#10684)
- The kernel now evaluates each part comparison (days, seconds, subseconds) once. - A population count of the valid rows tells if the comparison decides the result. - When no row is valid, the comparison does not decide the result. This matches the unknown min and max statistics of such an array. --------- Signed-off-by: Robert Kruszewski <robert@spiraldb.com>
1 parent 6f7091d commit 824cee7

1 file changed

Lines changed: 59 additions & 20 deletions

File tree

‎encodings/datetime-parts/src/compute/compare.rs‎

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use vortex_array::ArrayRef;
55
use vortex_array::ArrayView;
66
use vortex_array::ExecutionCtx;
77
use vortex_array::IntoArray;
8+
use vortex_array::arrays::BoolArray;
89
use vortex_array::arrays::ConstantArray;
10+
use vortex_array::arrays::bool::BoolArrayExt;
911
use vortex_array::builtins::ArrayBuiltins;
1012
use vortex_array::dtype::DType;
1113
use vortex_array::dtype::Nullability;
@@ -16,6 +18,7 @@ use vortex_array::scalar_fn::fns::operators::CompareOperator;
1618
use vortex_array::scalar_fn::fns::operators::Operator;
1719
use vortex_array::validity::Validity;
1820
use vortex_error::VortexResult;
21+
use vortex_mask::AllOr;
1922

2023
use crate::array::DateTimeParts;
2124
use crate::array::DateTimePartsArraySlotsExt;
@@ -87,9 +90,10 @@ fn compare_eq(
8790
nullability: Nullability,
8891
ctx: &mut ExecutionCtx,
8992
) -> VortexResult<ArrayRef> {
90-
let mut comparison = compare_dtp(lhs.days(), ts_parts.days, CompareOperator::Eq, nullability)?;
91-
if comparison.statistics().compute_max::<bool>(ctx) == Some(false) {
92-
return Ok(comparison);
93+
let mut comparison = compare_dtp(lhs.days(), ts_parts.days, CompareOperator::Eq, nullability)?
94+
.execute::<BoolArray>(ctx)?;
95+
if valid_rows_all(&comparison, false, ctx)? {
96+
return Ok(comparison.into_array());
9397
}
9498

9599
comparison = compare_dtp(
@@ -98,10 +102,11 @@ fn compare_eq(
98102
CompareOperator::Eq,
99103
nullability,
100104
)?
101-
.binary(comparison, Operator::And)?;
105+
.binary(comparison.into_array(), Operator::And)?
106+
.execute::<BoolArray>(ctx)?;
102107

103-
if comparison.statistics().compute_max::<bool>(ctx) == Some(false) {
104-
return Ok(comparison);
108+
if valid_rows_all(&comparison, false, ctx)? {
109+
return Ok(comparison.into_array());
105110
}
106111

107112
compare_dtp(
@@ -110,7 +115,7 @@ fn compare_eq(
110115
CompareOperator::Eq,
111116
nullability,
112117
)?
113-
.binary(comparison, Operator::And)
118+
.binary(comparison.into_array(), Operator::And)
114119
}
115120

116121
fn compare_ne(
@@ -124,9 +129,10 @@ fn compare_ne(
124129
ts_parts.days,
125130
CompareOperator::NotEq,
126131
nullability,
127-
)?;
128-
if comparison.statistics().compute_min::<bool>(ctx) == Some(true) {
129-
return Ok(comparison);
132+
)?
133+
.execute::<BoolArray>(ctx)?;
134+
if valid_rows_all(&comparison, true, ctx)? {
135+
return Ok(comparison.into_array());
130136
}
131137

132138
comparison = compare_dtp(
@@ -135,10 +141,11 @@ fn compare_ne(
135141
CompareOperator::NotEq,
136142
nullability,
137143
)?
138-
.binary(comparison, Operator::Or)?;
144+
.binary(comparison.into_array(), Operator::Or)?
145+
.execute::<BoolArray>(ctx)?;
139146

140-
if comparison.statistics().compute_min::<bool>(ctx) == Some(true) {
141-
return Ok(comparison);
147+
if valid_rows_all(&comparison, true, ctx)? {
148+
return Ok(comparison.into_array());
142149
}
143150

144151
compare_dtp(
@@ -147,7 +154,7 @@ fn compare_ne(
147154
CompareOperator::NotEq,
148155
nullability,
149156
)?
150-
.binary(comparison, Operator::Or)
157+
.binary(comparison.into_array(), Operator::Or)
151158
}
152159

153160
/// Orders timestamps by their parts.
@@ -170,14 +177,17 @@ fn compare_ordered(
170177
}
171178
};
172179

173-
let days_strict = compare_dtp(lhs.days(), ts_parts.days, strict, nullability)?;
174-
if days_strict.statistics().compute_min::<bool>(ctx) == Some(true) {
175-
return Ok(days_strict);
180+
let days_strict =
181+
compare_dtp(lhs.days(), ts_parts.days, strict, nullability)?.execute::<BoolArray>(ctx)?;
182+
if valid_rows_all(&days_strict, true, ctx)? {
183+
return Ok(days_strict.into_array());
176184
}
177-
let days_eq = compare_dtp(lhs.days(), ts_parts.days, CompareOperator::Eq, nullability)?;
178-
if days_eq.statistics().compute_max::<bool>(ctx) == Some(false) {
179-
return Ok(days_strict);
185+
let days_eq = compare_dtp(lhs.days(), ts_parts.days, CompareOperator::Eq, nullability)?
186+
.execute::<BoolArray>(ctx)?;
187+
if valid_rows_all(&days_eq, false, ctx)? {
188+
return Ok(days_strict.into_array());
180189
}
190+
let (days_strict, days_eq) = (days_strict.into_array(), days_eq.into_array());
181191

182192
let seconds_strict = compare_dtp(lhs.seconds(), ts_parts.seconds, strict, nullability)?;
183193
let seconds_eq = compare_dtp(
@@ -193,6 +203,35 @@ fn compare_ordered(
193203
days_strict.binary(days_eq.binary(within_day, Operator::And)?, Operator::Or)
194204
}
195205

206+
/// Whether every valid row of `comparison` is `value`. This is `false` when no row is valid, as the
207+
/// min and max statistics of such an array are unknown.
208+
///
209+
/// The comparison is already evaluated, so a population count answers this, where the min and max
210+
/// statistics of a lazy comparison would evaluate it again.
211+
fn valid_rows_all(
212+
comparison: &BoolArray,
213+
value: bool,
214+
ctx: &mut ExecutionCtx,
215+
) -> VortexResult<bool> {
216+
let bits = comparison.to_bit_buffer();
217+
let valid = comparison.validity()?.execute_mask(comparison.len(), ctx)?;
218+
let (valid_count, true_count) = match valid.bit_buffer() {
219+
AllOr::All => (bits.len(), bits.true_count()),
220+
AllOr::None => return Ok(false),
221+
AllOr::Some(valid_bits) => (valid.true_count(), (&bits & valid_bits).true_count()),
222+
};
223+
224+
if valid_count == 0 {
225+
return Ok(false);
226+
}
227+
228+
Ok(if value {
229+
true_count == valid_count
230+
} else {
231+
true_count == 0
232+
})
233+
}
234+
196235
fn compare_dtp(
197236
lhs: &ArrayRef,
198237
rhs: i32,

0 commit comments

Comments
 (0)