datafusion_extra_functions/
mode.rs1use crate::common;
19
20use datafusion::arrow::datatypes::{
21 DataType, Date32Type, Date64Type, Field, Float16Type, Float32Type, Float64Type, Int8Type,
22 Int16Type, Int32Type, Int64Type, Time32MillisecondType, Time32SecondType,
23 Time64MicrosecondType, Time64NanosecondType, TimeUnit, TimestampMicrosecondType,
24 TimestampMillisecondType, TimestampNanosecondType, TimestampSecondType, UInt8Type, UInt16Type,
25 UInt32Type, UInt64Type,
26};
27use datafusion::{arrow, common as df_common, error, logical_expr};
28use std::{fmt, hash};
29
30make_udaf_expr_and_func!(
31 ModeFunction,
32 mode,
33 x,
34 "Calculates the most frequent value.",
35 mode_udaf
36);
37
38#[derive(Eq, Hash, PartialEq)]
44pub struct ModeFunction {
45 signature: logical_expr::Signature,
46}
47
48impl fmt::Debug for ModeFunction {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.debug_struct("ModeFunction")
51 .field("signature", &self.signature)
52 .finish()
53 }
54}
55
56impl Default for ModeFunction {
57 fn default() -> Self {
58 Self::new()
59 }
60}
61
62impl ModeFunction {
63 pub fn new() -> Self {
64 Self {
65 signature: logical_expr::Signature::variadic_any(logical_expr::Volatility::Immutable),
66 }
67 }
68}
69
70impl logical_expr::AggregateUDFImpl for ModeFunction {
71 fn name(&self) -> &str {
72 "mode"
73 }
74
75 fn signature(&self) -> &logical_expr::Signature {
76 &self.signature
77 }
78
79 fn return_type(&self, arg_types: &[DataType]) -> error::Result<DataType> {
80 Ok(arg_types[0].clone())
81 }
82
83 fn state_fields(
84 &self,
85 args: logical_expr::function::StateFieldsArgs,
86 ) -> error::Result<Vec<arrow::datatypes::FieldRef>> {
87 let value_type = match args.input_fields[0].data_type() {
88 DataType::Utf8View => DataType::Utf8,
89 other => other.clone(),
90 };
91
92 Ok(vec![
93 Field::new_list("values", Field::new_list_field(value_type, true), true).into(),
94 Field::new_list(
95 "frequencies",
96 Field::new_list_field(DataType::Int64, true),
97 true,
98 )
99 .into(),
100 ])
101 }
102
103 fn accumulator(
104 &self,
105 acc_args: logical_expr::function::AccumulatorArgs,
106 ) -> error::Result<Box<dyn logical_expr::Accumulator>> {
107 fn primitive<T>(data_type: &DataType) -> Box<dyn logical_expr::Accumulator>
108 where
109 T: arrow::array::ArrowPrimitiveType + Send + fmt::Debug,
110 T::Native: Eq + hash::Hash + Clone + PartialOrd + fmt::Debug,
111 {
112 Box::new(common::mode::PrimitiveModeAccumulator::<T>::new(data_type))
113 }
114
115 fn float<T>(data_type: &DataType) -> Box<dyn logical_expr::Accumulator>
116 where
117 T: arrow::array::ArrowPrimitiveType + Send + fmt::Debug,
118 T::Native: PartialOrd + fmt::Debug + Clone,
119 {
120 Box::new(common::mode::FloatModeAccumulator::<T>::new(data_type))
121 }
122
123 let data_type = &acc_args.exprs[0].data_type(acc_args.schema)?;
124
125 Ok(match data_type {
126 DataType::Int8 => primitive::<Int8Type>(data_type),
127 DataType::Int16 => primitive::<Int16Type>(data_type),
128 DataType::Int32 => primitive::<Int32Type>(data_type),
129 DataType::Int64 => primitive::<Int64Type>(data_type),
130 DataType::UInt8 => primitive::<UInt8Type>(data_type),
131 DataType::UInt16 => primitive::<UInt16Type>(data_type),
132 DataType::UInt32 => primitive::<UInt32Type>(data_type),
133 DataType::UInt64 => primitive::<UInt64Type>(data_type),
134
135 DataType::Date32 => primitive::<Date32Type>(data_type),
136 DataType::Date64 => primitive::<Date64Type>(data_type),
137 DataType::Time32(TimeUnit::Second) => primitive::<Time32SecondType>(data_type),
138 DataType::Time32(TimeUnit::Millisecond) => {
139 primitive::<Time32MillisecondType>(data_type)
140 }
141 DataType::Time64(TimeUnit::Microsecond) => {
142 primitive::<Time64MicrosecondType>(data_type)
143 }
144 DataType::Time64(TimeUnit::Nanosecond) => primitive::<Time64NanosecondType>(data_type),
145 DataType::Timestamp(TimeUnit::Second, _) => primitive::<TimestampSecondType>(data_type),
146 DataType::Timestamp(TimeUnit::Millisecond, _) => {
147 primitive::<TimestampMillisecondType>(data_type)
148 }
149 DataType::Timestamp(TimeUnit::Microsecond, _) => {
150 primitive::<TimestampMicrosecondType>(data_type)
151 }
152 DataType::Timestamp(TimeUnit::Nanosecond, _) => {
153 primitive::<TimestampNanosecondType>(data_type)
154 }
155
156 DataType::Float16 => float::<Float16Type>(data_type),
157 DataType::Float32 => float::<Float32Type>(data_type),
158 DataType::Float64 => float::<Float64Type>(data_type),
159
160 DataType::Utf8 | DataType::Utf8View => {
161 Box::new(common::mode::BytesModeAccumulator::new(data_type))
162 }
163 _ => {
164 return df_common::not_impl_err!(
165 "Unsupported data type: {data_type:?} for mode function"
166 );
167 }
168 })
169 }
170}