Skip to content

Commit 1c8295c

Browse files
authored
feat: Support Union type in approx_distinct (#23714)
## Which issue does this PR close? - Relates to #22989 but does not close it. More types are coming. ## Rationale for this change - Support the Arrow type `Union` for `approx_distinct` ## What changes are included in this PR? - Enable `HLLAccumulator` and `HllGroupsAccumulator` to support `Union` - Tests ## Are these changes tested? Yes ## Are there any user-facing changes? Yes, `approx_distinct` supports now `Union` but no breaking changes.
1 parent e4f3df7 commit 1c8295c

3 files changed

Lines changed: 73 additions & 0 deletions

File tree

‎datafusion/functions-aggregate/src/approx_distinct.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,7 @@ impl AggregateUDFImpl for ApproxDistinct {
844844
| DataType::LargeListView(_)
845845
| DataType::Map(_, _)
846846
| DataType::Struct(_)
847+
| DataType::Union(_, _)
847848
| DataType::LargeBinary => Box::new(HLLAccumulator::new()),
848849
DataType::Null => {
849850
Box::new(NoopAccumulator::new(ScalarValue::UInt64(Some(0))))
@@ -922,6 +923,7 @@ fn is_hll_groups_type(data_type: &DataType) -> bool {
922923
| DataType::LargeListView(_)
923924
| DataType::Map(_, _)
924925
| DataType::Struct(_)
926+
| DataType::Union(_, _)
925927
)
926928
}
927929

‎datafusion/sqllogictest/src/test_context.rs‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ impl TestContext {
187187
info!("Registering table with union column");
188188
register_union_table(test_ctx.session_ctx())
189189
}
190+
"aggregate.slt" => {
191+
info!("Registering table with union column for approx_distinct");
192+
register_approx_distinct_union_table(test_ctx.session_ctx())
193+
}
190194
"dictionary_struct.slt" => {
191195
info!("Registering table with dictionary-encoded struct column");
192196
register_dictionary_struct_table(test_ctx.session_ctx());
@@ -593,6 +597,43 @@ fn register_union_table(ctx: &SessionContext) {
593597
ctx.register_batch("union_table", batch).unwrap();
594598
}
595599

600+
fn register_approx_distinct_union_table(ctx: &SessionContext) {
601+
let union = UnionArray::try_new(
602+
UnionFields::try_new(
603+
vec![0, 1],
604+
vec![
605+
Field::new("i", DataType::Int32, true),
606+
Field::new("s", DataType::Utf8, true),
607+
],
608+
)
609+
.unwrap(),
610+
ScalarBuffer::from(vec![0_i8, 0, 1, 1, 0, 0, 1, 0]),
611+
Some(ScalarBuffer::from(vec![0, 1, 0, 1, 2, 3, 2, 4])),
612+
vec![
613+
Arc::new(Int32Array::from(vec![
614+
Some(1),
615+
Some(1),
616+
None,
617+
None,
618+
Some(5),
619+
])),
620+
Arc::new(StringArray::from(vec![Some("x"), Some("y"), None])),
621+
],
622+
)
623+
.unwrap();
624+
625+
let schema = Schema::new(vec![
626+
Field::new("g", DataType::Int32, false),
627+
Field::new("u", union.data_type().clone(), false),
628+
]);
629+
630+
let g = Arc::new(Int32Array::from(vec![1, 1, 1, 2, 2, 3, 3, 4]));
631+
let batch = RecordBatch::try_new(Arc::new(schema), vec![g, Arc::new(union)]).unwrap();
632+
633+
ctx.register_batch("approx_distinct_union_test", batch)
634+
.unwrap();
635+
}
636+
596637
fn register_dictionary_struct_table(ctx: &SessionContext) {
597638
// Build deduplicated struct values: 3 unique structs
598639
let names = Arc::new(StringArray::from(vec!["Alice", "Bob", "Carol"])) as ArrayRef;

‎datafusion/sqllogictest/test_files/aggregate.slt‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2171,6 +2171,36 @@ SELECT approx_distinct(s) FROM approx_distinct_struct_test;
21712171
statement ok
21722172
DROP TABLE approx_distinct_struct_test;
21732173

2174+
# Union
2175+
# `approx_distinct_union_test` (g INT, u UNION<i: Int32, s: Utf8>) is registered
2176+
# in test_context.rs because a union value cannot be constructed from SQL.
2177+
2178+
# Union non-grouped
2179+
query I
2180+
SELECT approx_distinct(u) FROM approx_distinct_union_test WHERE g = 1;
2181+
----
2182+
2
2183+
2184+
# Union grouped
2185+
# Group 1 -> {i:1, i:1, s:"x"}=2,
2186+
# Group 2 -> {s:"y"}=1 (NULL excluded),
2187+
# Group 3 -> all null=0,
2188+
# Group 4 -> {i:5}=1
2189+
query II
2190+
SELECT g, approx_distinct(u) FROM approx_distinct_union_test GROUP BY g ORDER BY g;
2191+
----
2192+
1 2
2193+
2 1
2194+
3 0
2195+
4 1
2196+
2197+
# The non-group path must agree with the grouped path on
2198+
# the same data, and distinct union values across groups are still counted overall.
2199+
query I
2200+
SELECT approx_distinct(u) FROM approx_distinct_union_test;
2201+
----
2202+
4
2203+
21742204
# Integers (Int32): group 1 -> {10,20}=2, group 2 -> {30,40}=2, group 3 -> 0, group 4 -> {50}=1
21752205
query II
21762206
SELECT g, approx_distinct(i) FROM approx_distinct_group_test GROUP BY g ORDER BY g;

0 commit comments

Comments
 (0)