Skip to main content

datafusion_functions_aggregate/
lib.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18#![cfg_attr(test, allow(clippy::needless_pass_by_value))]
19#![doc(
20    html_logo_url = "https://raw.githubusercontent.com/apache/datafusion/19fe44cf2f30cbdd63d4a4f52c74055163c6cc38/docs/logos/standalone_logo/logo_original.svg",
21    html_favicon_url = "https://raw.githubusercontent.com/apache/datafusion/19fe44cf2f30cbdd63d4a4f52c74055163c6cc38/docs/logos/standalone_logo/logo_original.svg"
22)]
23#![cfg_attr(docsrs, feature(doc_cfg))]
24// Make sure fast / cheap clones on Arc are explicit:
25// https://github.com/apache/datafusion/issues/11143
26#![deny(clippy::clone_on_ref_ptr)]
27
28//! Aggregate Function packages for [DataFusion].
29//!
30//! This crate contains a collection of various aggregate function packages for DataFusion,
31//! implemented using the extension API. Users may wish to control which functions
32//! are available to control the binary size of their application as well as
33//! use dialect specific implementations of functions (e.g. Spark vs Postgres)
34//!
35//! Each package is implemented as a separate
36//! module, activated by a feature flag.
37//!
38//! [DataFusion]: https://crates.io/crates/datafusion
39//!
40//! # Available Packages
41//! See the list of [modules](#modules) in this crate for available packages.
42//!
43//! # Using A Package
44//! You can register all functions in all packages using the [`register_all`] function.
45//!
46//! Each package also exports an `expr_fn` submodule to help create [`Expr`]s that invoke
47//! functions using a fluent style. For example:
48//!
49//![`Expr`]: datafusion_expr::Expr
50//!
51//! # Implementing A New Package
52//!
53//! To add a new package to this crate, you should follow the model of existing
54//! packages. The high level steps are:
55//!
56//! 1. Create a new module with the appropriate [AggregateUDF] implementations.
57//!
58//! 2. Use the macros in [`macros`] to create standard entry points.
59//!
60//! 3. Add a new feature to `Cargo.toml`, with any optional dependencies
61//!
62//! 4. Use the `make_package!` macro to expose the module when the
63//!    feature is enabled.
64
65#[macro_use]
66pub mod macros;
67
68pub mod any_value;
69pub mod approx_distinct;
70pub mod approx_median;
71pub mod approx_percentile_cont;
72pub mod approx_percentile_cont_with_weight;
73pub mod array_agg;
74pub mod average;
75pub mod bit_and_or_xor;
76pub mod bool_and_or;
77pub mod correlation;
78pub mod count;
79pub mod covariance;
80pub mod first_last;
81pub mod grouping;
82pub mod hyperloglog;
83pub mod median;
84pub mod min_max;
85pub mod nth_value;
86pub mod percentile_cont;
87pub mod regr;
88pub mod stddev;
89pub mod string_agg;
90pub mod sum;
91pub mod variance;
92
93pub mod planner;
94mod utils;
95
96use crate::approx_percentile_cont::approx_percentile_cont_udaf;
97use crate::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight_udaf;
98use datafusion_common::Result;
99use datafusion_execution::FunctionRegistry;
100use datafusion_expr::AggregateUDF;
101use log::debug;
102use std::sync::Arc;
103
104/// Fluent-style API for creating `Expr`s
105pub mod expr_fn {
106    pub use super::any_value::any_value;
107    pub use super::approx_distinct::approx_distinct;
108    pub use super::approx_median::approx_median;
109    pub use super::approx_percentile_cont::approx_percentile_cont;
110    pub use super::approx_percentile_cont_with_weight::approx_percentile_cont_with_weight;
111    pub use super::array_agg::array_agg;
112    pub use super::average::avg;
113    pub use super::average::avg_distinct;
114    pub use super::bit_and_or_xor::bit_and;
115    pub use super::bit_and_or_xor::bit_or;
116    pub use super::bit_and_or_xor::bit_xor;
117    pub use super::bool_and_or::bool_and;
118    pub use super::bool_and_or::bool_or;
119    pub use super::correlation::corr;
120    pub use super::count::count;
121    pub use super::count::count_distinct;
122    pub use super::covariance::covar_pop;
123    pub use super::covariance::covar_samp;
124    pub use super::first_last::first_value;
125    pub use super::first_last::last_value;
126    pub use super::grouping::grouping;
127    pub use super::median::median;
128    pub use super::min_max::max;
129    pub use super::min_max::min;
130    pub use super::nth_value::nth_value;
131    pub use super::percentile_cont::percentile_cont;
132    pub use super::regr::regr_avgx;
133    pub use super::regr::regr_avgy;
134    pub use super::regr::regr_count;
135    pub use super::regr::regr_intercept;
136    pub use super::regr::regr_r2;
137    pub use super::regr::regr_slope;
138    pub use super::regr::regr_sxx;
139    pub use super::regr::regr_sxy;
140    pub use super::regr::regr_syy;
141    pub use super::stddev::stddev;
142    pub use super::stddev::stddev_pop;
143    pub use super::sum::sum;
144    pub use super::sum::sum_distinct;
145    pub use super::variance::var_pop;
146    pub use super::variance::var_sample;
147}
148
149/// Returns all default aggregate functions
150pub fn all_default_aggregate_functions() -> Vec<Arc<AggregateUDF>> {
151    vec![
152        any_value::any_value_udaf(),
153        array_agg::array_agg_udaf(),
154        first_last::first_value_udaf(),
155        first_last::last_value_udaf(),
156        covariance::covar_samp_udaf(),
157        covariance::covar_pop_udaf(),
158        correlation::corr_udaf(),
159        sum::sum_udaf(),
160        min_max::max_udaf(),
161        min_max::min_udaf(),
162        median::median_udaf(),
163        count::count_udaf(),
164        regr::regr_slope_udaf(),
165        regr::regr_intercept_udaf(),
166        regr::regr_count_udaf(),
167        regr::regr_r2_udaf(),
168        regr::regr_avgx_udaf(),
169        regr::regr_avgy_udaf(),
170        regr::regr_sxx_udaf(),
171        regr::regr_syy_udaf(),
172        regr::regr_sxy_udaf(),
173        variance::var_samp_udaf(),
174        variance::var_pop_udaf(),
175        stddev::stddev_udaf(),
176        stddev::stddev_pop_udaf(),
177        approx_median::approx_median_udaf(),
178        approx_distinct::approx_distinct_udaf(),
179        approx_percentile_cont_udaf(),
180        approx_percentile_cont_with_weight_udaf(),
181        percentile_cont::percentile_cont_udaf(),
182        string_agg::string_agg_udaf(),
183        bit_and_or_xor::bit_and_udaf(),
184        bit_and_or_xor::bit_or_udaf(),
185        bit_and_or_xor::bit_xor_udaf(),
186        bool_and_or::bool_and_udaf(),
187        bool_and_or::bool_or_udaf(),
188        average::avg_udaf(),
189        grouping::grouping_udaf(),
190        nth_value::nth_value_udaf(),
191    ]
192}
193
194/// Registers all enabled packages with a [`FunctionRegistry`]
195pub fn register_all(registry: &mut dyn FunctionRegistry) -> Result<()> {
196    let functions: Vec<Arc<AggregateUDF>> = all_default_aggregate_functions();
197
198    functions.into_iter().try_for_each(|udf| {
199        let existing_udaf = registry.register_udaf(udf)?;
200        if let Some(existing_udaf) = existing_udaf {
201            debug!("Overwrite existing UDAF: {}", existing_udaf.name());
202        }
203        Ok(()) as Result<()>
204    })?;
205
206    Ok(())
207}
208
209#[cfg(test)]
210mod tests {
211    use crate::all_default_aggregate_functions;
212    use datafusion_common::Result;
213    use std::collections::HashSet;
214
215    #[test]
216    fn test_no_duplicate_name() -> Result<()> {
217        let mut names = HashSet::new();
218        for func in all_default_aggregate_functions() {
219            assert!(
220                names.insert(func.name().to_string().to_lowercase()),
221                "duplicate function name: {}",
222                func.name()
223            );
224            for alias in func.aliases() {
225                assert!(
226                    names.insert(alias.to_string().to_lowercase()),
227                    "duplicate function name: {alias}"
228                );
229            }
230        }
231        Ok(())
232    }
233}