Skip to content

Commit 23e864c

Browse files
author
B Vadlamani
committed
add groups bench approx distinct
1 parent 36b1927 commit 23e864c

1 file changed

Lines changed: 132 additions & 3 deletions

File tree

datafusion/functions-aggregate/benches/approx_distinct.rs

Lines changed: 132 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@
1818
use std::sync::Arc;
1919

2020
use arrow::array::{
21-
ArrayRef, Int8Array, Int16Array, Int64Array, StringArray, StringViewArray,
21+
Array, ArrayRef, Int8Array, Int16Array, Int64Array, StringArray, StringViewArray,
2222
UInt8Array, UInt16Array,
2323
};
2424
use arrow::datatypes::{DataType, Field, Schema};
2525
use criterion::{Criterion, criterion_group, criterion_main};
2626
use datafusion_expr::function::AccumulatorArgs;
27-
use datafusion_expr::{Accumulator, AggregateUDFImpl};
27+
use datafusion_expr::{Accumulator, AggregateUDFImpl, EmitTo};
2828
use datafusion_functions_aggregate::approx_distinct::ApproxDistinct;
2929
use datafusion_physical_expr::expressions::col;
3030
use rand::rngs::StdRng;
@@ -216,5 +216,134 @@ fn approx_distinct_benchmark(c: &mut Criterion) {
216216
});
217217
}
218218

219-
criterion_group!(benches, approx_distinct_benchmark);
219+
fn prepare_args(data_type: DataType) -> (Arc<Schema>, AccumulatorArgs<'static>) {
220+
let schema = Arc::new(Schema::new(vec![Field::new("f", data_type, true)]));
221+
let schema_leaked: &'static Schema = Box::leak(Box::new((*schema).clone()));
222+
let expr = col("f", schema_leaked).unwrap();
223+
let expr_leaked: &'static _ = Box::leak(Box::new(expr));
224+
let return_field: Arc<Field> = Field::new("f", DataType::UInt64, true).into();
225+
let return_field_leaked: &'static _ = Box::leak(Box::new(return_field.clone()));
226+
let expr_field = expr_leaked.return_field(schema_leaked).unwrap();
227+
let expr_field_leaked: &'static _ = Box::leak(Box::new(expr_field));
228+
229+
let accumulator_args = AccumulatorArgs {
230+
return_field: return_field_leaked.clone(),
231+
schema: schema_leaked,
232+
expr_fields: std::slice::from_ref(expr_field_leaked),
233+
ignore_nulls: false,
234+
order_bys: &[],
235+
is_reversed: false,
236+
name: "approx_distinct(f)",
237+
is_distinct: false,
238+
exprs: std::slice::from_ref(expr_leaked),
239+
};
240+
(schema, accumulator_args)
241+
}
242+
243+
fn create_uniform_groups(num_groups: usize) -> Vec<usize> {
244+
let mut rng = StdRng::seed_from_u64(42);
245+
(0..BATCH_SIZE)
246+
.map(|_| rng.random_range(0..num_groups))
247+
.collect()
248+
}
249+
250+
// 80% of rows land in 20% of groups
251+
fn create_skewed_groups(num_groups: usize) -> Vec<usize> {
252+
let mut rng = StdRng::seed_from_u64(42);
253+
let hot_groups = (num_groups / 5).max(1);
254+
(0..BATCH_SIZE)
255+
.map(|_| {
256+
if rng.random_range(0..100) < 80 {
257+
rng.random_range(0..hot_groups)
258+
} else {
259+
rng.random_range(0..num_groups)
260+
}
261+
})
262+
.collect()
263+
}
264+
265+
fn approx_distinct_groups_benchmark(c: &mut Criterion) {
266+
let approx_fn = ApproxDistinct::new();
267+
268+
let group_counts = [100, 1000, 10000];
269+
let cardinalities = [("low", 20), ("mid", 80), ("high", 99)];
270+
let distributions = ["uniform", "skewed"];
271+
272+
for num_groups in group_counts {
273+
for (card_name, distinct_pct) in cardinalities {
274+
for dist in distributions {
275+
let name = format!("i64_g{num_groups}_{card_name}_{dist}");
276+
let n_distinct = BATCH_SIZE * distinct_pct / 100;
277+
let values = Arc::new(create_i64_array(n_distinct)) as ArrayRef;
278+
let group_indices = if dist == "uniform" {
279+
create_uniform_groups(num_groups)
280+
} else {
281+
create_skewed_groups(num_groups)
282+
};
283+
284+
let (_schema, args) = prepare_args(DataType::Int64);
285+
286+
if approx_fn.groups_accumulator_supported(args.clone()) {
287+
c.bench_function(&format!("approx_distinct_groups {name}"), |b| {
288+
b.iter(|| {
289+
let mut acc = approx_fn
290+
.create_groups_accumulator(args.clone())
291+
.unwrap();
292+
acc.update_batch(
293+
std::slice::from_ref(&values),
294+
&group_indices,
295+
None,
296+
num_groups,
297+
)
298+
.unwrap();
299+
acc.evaluate(EmitTo::All).unwrap()
300+
})
301+
});
302+
} else {
303+
let arr = values.as_any().downcast_ref::<Int64Array>().unwrap();
304+
let mut group_rows: Vec<Vec<i64>> = vec![Vec::new(); num_groups];
305+
for (idx, &group_idx) in group_indices.iter().enumerate() {
306+
if arr.is_valid(idx) {
307+
group_rows[group_idx].push(arr.value(idx));
308+
}
309+
}
310+
let group_arrays: Vec<ArrayRef> = group_rows
311+
.iter()
312+
.map(|rows| {
313+
Arc::new(Int64Array::from(rows.clone())) as ArrayRef
314+
})
315+
.collect();
316+
317+
c.bench_function(&format!("approx_distinct_groups {name}"), |b| {
318+
b.iter(|| {
319+
let mut accumulators: Vec<_> = (0..num_groups)
320+
.map(|_| prepare_accumulator(DataType::Int64))
321+
.collect();
322+
323+
for (group_idx, batch) in group_arrays.iter().enumerate()
324+
{
325+
if !batch.is_empty() {
326+
accumulators[group_idx]
327+
.update_batch(std::slice::from_ref(batch))
328+
.unwrap();
329+
}
330+
}
331+
332+
let _results: Vec<_> = accumulators
333+
.iter_mut()
334+
.map(|acc| acc.evaluate().unwrap())
335+
.collect();
336+
})
337+
});
338+
}
339+
}
340+
}
341+
}
342+
}
343+
344+
criterion_group!(
345+
benches,
346+
approx_distinct_benchmark,
347+
approx_distinct_groups_benchmark
348+
);
220349
criterion_main!(benches);

0 commit comments

Comments
 (0)