datafusion_functions_aggregate/
nth_value.rs1use std::collections::VecDeque;
22use std::mem::{size_of, size_of_val};
23use std::sync::Arc;
24
25use arrow::array::{ArrayRef, AsArray, StructArray, new_empty_array};
26use arrow::datatypes::{DataType, Field, FieldRef, Fields};
27
28use datafusion_common::utils::{SingleRowListArrayBuilder, get_row_at_idx};
29use datafusion_common::{
30 Result, ScalarValue, assert_or_internal_err, exec_err, not_impl_err,
31};
32use datafusion_expr::function::{AccumulatorArgs, StateFieldsArgs};
33use datafusion_expr::utils::format_state_name;
34use datafusion_expr::{
35 Accumulator, AggregateUDFImpl, Documentation, ExprFunctionExt, ReversedUDAF,
36 Signature, SortExpr, Volatility, lit,
37};
38use datafusion_functions_aggregate_common::merge_arrays::merge_ordered_arrays;
39use datafusion_functions_aggregate_common::utils::ordering_fields;
40use datafusion_macros::user_doc;
41use datafusion_physical_expr::expressions::Literal;
42use datafusion_physical_expr_common::sort_expr::{LexOrdering, PhysicalSortExpr};
43
44create_func!(NthValueAgg, nth_value_udaf);
45
46pub fn nth_value(
48 expr: datafusion_expr::Expr,
49 n: i64,
50 order_by: Vec<SortExpr>,
51) -> datafusion_expr::Expr {
52 let args = vec![expr, lit(n)];
53 if !order_by.is_empty() {
54 nth_value_udaf()
55 .call(args)
56 .order_by(order_by)
57 .build()
58 .unwrap()
59 } else {
60 nth_value_udaf().call(args)
61 }
62}
63
64#[user_doc(
65 doc_section(label = "Statistical Functions"),
66 description = "Returns the nth value in a group of values.",
67 syntax_example = "nth_value(expression, n ORDER BY expression)",
68 sql_example = r#"```sql
69> SELECT dept_id, salary, NTH_VALUE(salary, 2) OVER (PARTITION BY dept_id ORDER BY salary ASC) AS second_salary_by_dept
70 FROM employee;
71+---------+--------+-------------------------+
72| dept_id | salary | second_salary_by_dept |
73+---------+--------+-------------------------+
74| 1 | 30000 | NULL |
75| 1 | 40000 | 40000 |
76| 1 | 50000 | 40000 |
77| 2 | 35000 | NULL |
78| 2 | 45000 | 45000 |
79+---------+--------+-------------------------+
80```"#,
81 argument(
82 name = "expression",
83 description = "The column or expression to retrieve the nth value from."
84 ),
85 argument(
86 name = "n",
87 description = "The position (nth) of the value to retrieve, based on the ordering."
88 )
89)]
90#[derive(Debug, PartialEq, Eq, Hash)]
94pub struct NthValueAgg {
95 signature: Signature,
96}
97
98impl NthValueAgg {
99 pub fn new() -> Self {
101 Self {
102 signature: Signature::any(2, Volatility::Immutable),
103 }
104 }
105}
106
107impl Default for NthValueAgg {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl AggregateUDFImpl for NthValueAgg {
114 fn name(&self) -> &str {
115 "nth_value"
116 }
117
118 fn signature(&self) -> &Signature {
119 &self.signature
120 }
121
122 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
123 Ok(arg_types[0].clone())
124 }
125
126 fn accumulator(&self, acc_args: AccumulatorArgs) -> Result<Box<dyn Accumulator>> {
127 let n = match acc_args.exprs[1]
128 .downcast_ref::<Literal>()
129 .map(|lit| lit.value())
130 {
131 Some(ScalarValue::Int64(Some(value))) => {
132 if acc_args.is_reversed {
133 -*value
134 } else {
135 *value
136 }
137 }
138 _ => {
139 return not_impl_err!(
140 "{} not supported for n: {}",
141 self.name(),
142 &acc_args.exprs[1]
143 );
144 }
145 };
146
147 let Some(ordering) = LexOrdering::new(acc_args.order_bys.to_vec()) else {
148 return TrivialNthValueAccumulator::try_new(
149 n,
150 acc_args.return_field.data_type(),
151 )
152 .map(|acc| Box::new(acc) as _);
153 };
154 let ordering_dtypes = ordering
155 .iter()
156 .map(|e| e.expr.data_type(acc_args.schema))
157 .collect::<Result<Vec<_>>>()?;
158
159 let data_type = acc_args.expr_fields[0].data_type();
160 NthValueAccumulator::try_new(n, data_type, &ordering_dtypes, ordering)
161 .map(|acc| Box::new(acc) as _)
162 }
163
164 fn state_fields(&self, args: StateFieldsArgs) -> Result<Vec<FieldRef>> {
165 let mut fields = vec![Field::new_list(
166 format_state_name(self.name(), "nth_value"),
167 Field::new_list_field(args.input_fields[0].data_type().clone(), true),
169 false,
170 )];
171 let orderings = args.ordering_fields.to_vec();
172 if !orderings.is_empty() {
173 fields.push(Field::new_list(
174 format_state_name(self.name(), "nth_value_orderings"),
175 Field::new_list_field(DataType::Struct(Fields::from(orderings)), true),
176 false,
177 ));
178 }
179 Ok(fields.into_iter().map(Arc::new).collect())
180 }
181
182 fn reverse_expr(&self) -> ReversedUDAF {
183 ReversedUDAF::Reversed(nth_value_udaf())
184 }
185
186 fn documentation(&self) -> Option<&Documentation> {
187 self.doc()
188 }
189}
190
191#[derive(Debug)]
192pub struct TrivialNthValueAccumulator {
193 n: i64,
195 values: VecDeque<ScalarValue>,
197 datatype: DataType,
199}
200
201impl TrivialNthValueAccumulator {
202 pub fn try_new(n: i64, datatype: &DataType) -> Result<Self> {
205 assert_or_internal_err!(
207 n != 0,
208 "Nth value indices are 1 based. 0 is invalid index"
209 );
210 Ok(Self {
211 n,
212 values: VecDeque::new(),
213 datatype: datatype.clone(),
214 })
215 }
216
217 fn append_new_data(
220 &mut self,
221 values: &[ArrayRef],
222 fetch: Option<usize>,
223 ) -> Result<()> {
224 let n_row = values[0].len();
225 let n_to_add = if let Some(fetch) = fetch {
226 std::cmp::min(fetch, n_row)
227 } else {
228 n_row
229 };
230 for index in 0..n_to_add {
231 let mut row = get_row_at_idx(values, index)?;
232 self.values.push_back(row.swap_remove(0));
233 }
235 Ok(())
236 }
237}
238
239impl Accumulator for TrivialNthValueAccumulator {
240 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
243 if !values.is_empty() {
244 let n_required = self.n.unsigned_abs() as usize;
245 let from_start = self.n > 0;
246 if from_start {
247 let n_remaining = n_required.saturating_sub(self.values.len());
249 self.append_new_data(values, Some(n_remaining))?;
250 } else {
251 self.append_new_data(values, None)?;
253 let start_offset = self.values.len().saturating_sub(n_required);
254 if start_offset > 0 {
255 self.values.drain(0..start_offset);
256 }
257 }
258 }
259 Ok(())
260 }
261
262 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
263 if !states.is_empty() {
264 let n_required = self.n.unsigned_abs() as usize;
266 let array_agg_res = ScalarValue::convert_array_to_scalar_vec(&states[0])?;
267 for v in array_agg_res.into_iter().flatten() {
268 self.values.extend(v);
269 if self.values.len() > n_required {
270 break;
272 }
273 }
274 }
275 Ok(())
276 }
277
278 fn state(&mut self) -> Result<Vec<ScalarValue>> {
279 let mut values_cloned = self.values.clone();
280 let values_slice = values_cloned.make_contiguous();
281 Ok(vec![ScalarValue::List(ScalarValue::new_list_nullable(
282 values_slice,
283 &self.datatype,
284 ))])
285 }
286
287 fn evaluate(&mut self) -> Result<ScalarValue> {
288 let n_required = self.n.unsigned_abs() as usize;
289 let from_start = self.n > 0;
290 let nth_value_idx = if from_start {
291 let forward_idx = n_required - 1;
293 (forward_idx < self.values.len()).then_some(forward_idx)
294 } else {
295 self.values.len().checked_sub(n_required)
297 };
298 if let Some(idx) = nth_value_idx {
299 Ok(self.values[idx].clone())
300 } else {
301 ScalarValue::try_from(self.datatype.clone())
302 }
303 }
304
305 fn size(&self) -> usize {
306 size_of_val(self) + ScalarValue::size_of_vec_deque(&self.values)
307 - size_of_val(&self.values)
308 + size_of::<DataType>()
309 }
310}
311
312#[derive(Debug)]
313pub struct NthValueAccumulator {
314 n: i64,
316 values: VecDeque<ScalarValue>,
318 ordering_values: VecDeque<Vec<ScalarValue>>,
323 datatypes: Vec<DataType>,
326 ordering_req: LexOrdering,
328}
329
330impl NthValueAccumulator {
331 pub fn try_new(
334 n: i64,
335 datatype: &DataType,
336 ordering_dtypes: &[DataType],
337 ordering_req: LexOrdering,
338 ) -> Result<Self> {
339 assert_or_internal_err!(
341 n != 0,
342 "Nth value indices are 1 based. 0 is invalid index"
343 );
344 let mut datatypes = vec![datatype.clone()];
345 datatypes.extend(ordering_dtypes.iter().cloned());
346 Ok(Self {
347 n,
348 values: VecDeque::new(),
349 ordering_values: VecDeque::new(),
350 datatypes,
351 ordering_req,
352 })
353 }
354
355 fn evaluate_orderings(&self) -> Result<ScalarValue> {
356 let fields = ordering_fields(&self.ordering_req, &self.datatypes[1..]);
357
358 let mut column_wise_ordering_values = vec![];
359 let num_columns = fields.len();
360 for i in 0..num_columns {
361 let column_values = self
362 .ordering_values
363 .iter()
364 .map(|x| x[i].clone())
365 .collect::<Vec<_>>();
366 let array = if column_values.is_empty() {
367 new_empty_array(fields[i].data_type())
368 } else {
369 ScalarValue::iter_to_array(column_values)?
370 };
371 column_wise_ordering_values.push(array);
372 }
373
374 let struct_field = Fields::from(fields);
375 let ordering_array =
376 StructArray::try_new(struct_field, column_wise_ordering_values, None)?;
377
378 Ok(SingleRowListArrayBuilder::new(Arc::new(ordering_array)).build_list_scalar())
379 }
380
381 fn evaluate_values(&self) -> ScalarValue {
382 let mut values_cloned = self.values.clone();
383 let values_slice = values_cloned.make_contiguous();
384 ScalarValue::List(ScalarValue::new_list_nullable(
385 values_slice,
386 &self.datatypes[0],
387 ))
388 }
389
390 fn append_new_data(
393 &mut self,
394 values: &[ArrayRef],
395 fetch: Option<usize>,
396 ) -> Result<()> {
397 let n_row = values[0].len();
398 let n_to_add = if let Some(fetch) = fetch {
399 std::cmp::min(fetch, n_row)
400 } else {
401 n_row
402 };
403 for index in 0..n_to_add {
404 let row = get_row_at_idx(values, index)?;
405 self.values.push_back(row[0].clone());
406 self.ordering_values.push_back(row[2..].to_vec());
409 }
410 Ok(())
411 }
412}
413
414impl Accumulator for NthValueAccumulator {
415 fn update_batch(&mut self, values: &[ArrayRef]) -> Result<()> {
418 if values.is_empty() {
419 return Ok(());
420 }
421
422 let n_required = self.n.unsigned_abs() as usize;
423 let from_start = self.n > 0;
424 if from_start {
425 let n_remaining = n_required.saturating_sub(self.values.len());
427 self.append_new_data(values, Some(n_remaining))?;
428 } else {
429 self.append_new_data(values, None)?;
431 let start_offset = self.values.len().saturating_sub(n_required);
432 if start_offset > 0 {
433 self.values.drain(0..start_offset);
434 self.ordering_values.drain(0..start_offset);
435 }
436 }
437
438 Ok(())
439 }
440
441 fn merge_batch(&mut self, states: &[ArrayRef]) -> Result<()> {
442 if states.is_empty() {
443 return Ok(());
444 }
445 let Some(agg_orderings) = states[1].as_list_opt::<i32>() else {
451 return exec_err!("Expects to receive a list array");
452 };
453
454 let mut partition_values = vec![self.values.clone()];
456 let array_agg_res = ScalarValue::convert_array_to_scalar_vec(&states[0])?;
458 for v in array_agg_res.into_iter().flatten() {
459 partition_values.push(v.into());
460 }
461 let mut partition_ordering_values = vec![self.ordering_values.clone()];
463 let orderings = ScalarValue::convert_array_to_scalar_vec(agg_orderings)?;
464 for partition_ordering_rows in orderings.into_iter().flatten() {
466 let ordering_values = partition_ordering_rows.into_iter().map(|ordering_row| {
467 let ScalarValue::Struct(s_array) = ordering_row else {
468 return exec_err!(
469 "Expects to receive ScalarValue::Struct(Some(..), _) but got: {:?}",
470 ordering_row.data_type()
471 );
472 };
473 s_array
474 .columns()
475 .iter()
476 .map(|column| ScalarValue::try_from_array(column, 0))
477 .collect()
478 }).collect::<Result<VecDeque<_>>>()?;
479 partition_ordering_values.push(ordering_values);
480 }
481
482 let sort_options = self
483 .ordering_req
484 .iter()
485 .map(|sort_expr| sort_expr.options)
486 .collect::<Vec<_>>();
487 let (new_values, new_orderings) = merge_ordered_arrays(
488 &mut partition_values,
489 &mut partition_ordering_values,
490 &sort_options,
491 )?;
492 self.values = new_values.into();
493 self.ordering_values = new_orderings.into();
494 Ok(())
495 }
496
497 fn state(&mut self) -> Result<Vec<ScalarValue>> {
498 Ok(vec![self.evaluate_values(), self.evaluate_orderings()?])
499 }
500
501 fn evaluate(&mut self) -> Result<ScalarValue> {
502 let n_required = self.n.unsigned_abs() as usize;
503 let from_start = self.n > 0;
504 let nth_value_idx = if from_start {
505 let forward_idx = n_required - 1;
507 (forward_idx < self.values.len()).then_some(forward_idx)
508 } else {
509 self.values.len().checked_sub(n_required)
511 };
512 if let Some(idx) = nth_value_idx {
513 Ok(self.values[idx].clone())
514 } else {
515 ScalarValue::try_from(self.datatypes[0].clone())
516 }
517 }
518
519 fn size(&self) -> usize {
520 let mut total = size_of_val(self) + ScalarValue::size_of_vec_deque(&self.values)
521 - size_of_val(&self.values);
522
523 total += size_of::<Vec<ScalarValue>>() * self.ordering_values.capacity();
525 for row in &self.ordering_values {
526 total += ScalarValue::size_of_vec(row) - size_of_val(row);
527 }
528
529 total += size_of::<DataType>() * self.datatypes.capacity();
531 for dtype in &self.datatypes {
532 total += dtype.size() - size_of_val(dtype);
533 }
534
535 total += size_of::<PhysicalSortExpr>() * self.ordering_req.capacity();
537 total
539 }
540}