datafusion_spark/function/aggregate/
collect.rs1use arrow::array::ArrayRef;
19use arrow::datatypes::{DataType, Field, FieldRef};
20use datafusion_common::utils::SingleRowListArrayBuilder;
21use datafusion_common::{Result, ScalarValue, internal_err};
22use datafusion_expr::function::{AccumulatorArgs, StateFieldsArgs};
23use datafusion_expr::utils::format_state_name;
24use datafusion_expr::{Accumulator, AggregateUDFImpl, Signature, Volatility};
25use datafusion_functions_aggregate::array_agg::{
26 ArrayAggAccumulator, DistinctArrayAggAccumulator,
27};
28use std::sync::Arc;
29
30fn empty_list_scalar(list_type: &DataType) -> Result<ScalarValue> {
40 let DataType::List(field) = list_type else {
41 return internal_err!(
42 "collect_list/collect_set expected List return type, got {list_type:?}"
43 );
44 };
45 let empty = arrow::array::new_empty_array(field.data_type());
46 Ok(SingleRowListArrayBuilder::new(empty).build_list_scalar())
47}
48
49#[derive(Debug, PartialEq, Eq, Hash)]
51pub struct SparkCollectList {
52 signature: Signature,
53}
54
55impl Default for SparkCollectList {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl SparkCollectList {
62 pub fn new() -> Self {
63 Self {
64 signature: Signature::any(1, Volatility::Immutable),
65 }
66 }
67}
68
69impl AggregateUDFImpl for SparkCollectList {
70 fn name(&self) -> &str {
71 "collect_list"
72 }
73
74 fn signature(&self) -> &Signature {
75 &self.signature
76 }
77
78 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
79 Ok(DataType::List(Arc::new(Field::new_list_field(
80 arg_types[0].clone(),
81 true,
82 ))))
83 }
84
85 fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
86 Ok(vec![
87 Field::new_list(
88 format_state_name(args.name, "collect_list"),
89 Field::new_list_field(args.input_fields[0].data_type().clone(), true),
90 true,
91 )
92 .into(),
93 ])
94 }
95
96 fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
97 let element_type = acc_args.expr_fields[0].data_type().clone();
98 let ignore_nulls = true;
99 Ok(Box::new(NullToEmptyListAccumulator::new(
100 ArrayAggAccumulator::try_new(&element_type, ignore_nulls)?,
101 acc_args.return_type().clone(),
102 )))
103 }
104
105 fn default_value(&self, data_type: &DataType) -> Result<ScalarValue> {
106 empty_list_scalar(data_type)
107 }
108}
109
110#[derive(Debug, PartialEq, Eq, Hash)]
112pub struct SparkCollectSet {
113 signature: Signature,
114}
115
116impl Default for SparkCollectSet {
117 fn default() -> Self {
118 Self::new()
119 }
120}
121
122impl SparkCollectSet {
123 pub fn new() -> Self {
124 Self {
125 signature: Signature::any(1, Volatility::Immutable),
126 }
127 }
128}
129
130impl AggregateUDFImpl for SparkCollectSet {
131 fn name(&self) -> &str {
132 "collect_set"
133 }
134
135 fn signature(&self) -> &Signature {
136 &self.signature
137 }
138
139 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
140 Ok(DataType::List(Arc::new(Field::new_list_field(
141 arg_types[0].clone(),
142 true,
143 ))))
144 }
145
146 fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
147 Ok(vec![
148 Field::new_list(
149 format_state_name(args.name, "collect_set"),
150 Field::new_list_field(args.input_fields[0].data_type().clone(), true),
151 true,
152 )
153 .into(),
154 ])
155 }
156
157 fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
158 let element_type = acc_args.expr_fields[0].data_type().clone();
159 let ignore_nulls = true;
160 Ok(Box::new(NullToEmptyListAccumulator::new(
161 DistinctArrayAggAccumulator::try_new(&element_type, None, ignore_nulls)?,
162 acc_args.return_type().clone(),
163 )))
164 }
165
166 fn default_value(&self, data_type: &DataType) -> Result<ScalarValue> {
167 empty_list_scalar(data_type)
168 }
169}
170
171#[derive(Debug)]
174struct NullToEmptyListAccumulator<T: Accumulator> {
175 inner: T,
176 list_type: DataType,
177}
178
179impl<T: Accumulator> NullToEmptyListAccumulator<T> {
180 pub fn new(inner: T, list_type: DataType) -> Self {
181 Self { inner, list_type }
182 }
183}
184
185impl<T: Accumulator> Accumulator for NullToEmptyListAccumulator<T> {
186 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
187 self.inner.update_batch(values)
188 }
189
190 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
191 self.inner.merge_batch(states)
192 }
193
194 fn state(&mut self) -> Result<Vec<ScalarValue>> {
195 self.inner.state()
196 }
197
198 fn evaluate(&mut self) -> Result<ScalarValue> {
199 let result = self.inner.evaluate()?;
200 if result.is_null() {
201 empty_list_scalar(&self.list_type)
202 } else {
203 Ok(result)
204 }
205 }
206
207 fn retract_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
208 self.inner.retract_batch(values)
209 }
210
211 fn supports_retract_batch(&self) -> bool {
212 self.inner.supports_retract_batch()
213 }
214
215 fn size(&self) -> usize {
216 self.inner.size() + self.list_type.size()
217 }
218}