You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by li...@apache.org on 2022/06/17 03:07:55 UTC

[incubator-doris] branch master updated: [feature-wip](array-type) Add array aggregation functions (#10108)

This is an automated email from the ASF dual-hosted git repository.

lihaopeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 5e47b03595 [feature-wip](array-type) Add array aggregation functions (#10108)
5e47b03595 is described below

commit 5e47b0359562ad7f9350da5232109426e7f1a572
Author: Adonis Ling <ad...@gmail.com>
AuthorDate: Fri Jun 17 11:07:49 2022 +0800

    [feature-wip](array-type) Add array aggregation functions (#10108)
---
 be/src/vec/CMakeLists.txt                          |   1 +
 .../vec/aggregate_functions/aggregate_function.h   |  17 ++
 .../aggregate_function_product.h                   | 121 +++++++++
 be/src/vec/columns/column_decimal.h                |  19 ++
 be/src/vec/core/types.h                            |   7 +
 .../functions/array/function_array_aggregation.cpp | 287 +++++++++++++++++++++
 be/src/vec/functions/array/function_array_mapped.h |  76 ++++++
 .../functions/array/function_array_register.cpp    |   2 +
 be/src/vec/functions/function.h                    |   1 -
 be/src/vec/functions/simple_function_factory.h     |   3 +-
 be/test/CMakeLists.txt                             |   1 +
 .../function/function_array_aggregation_test.cpp   | 228 ++++++++++++++++
 be/test/vec/function/function_test_util.cpp        |  24 +-
 be/test/vec/function/function_test_util.h          |  83 +++++-
 .../sql-functions/array-functions/array_avg.md     |  61 +++++
 .../sql-functions/array-functions/array_max.md     |  61 +++++
 .../sql-functions/array-functions/array_min.md     |  61 +++++
 .../sql-functions/array-functions/array_product.md |  61 +++++
 .../sql-functions/array-functions/array_sum.md     |  61 +++++
 .../sql-functions/array-functions/array_avg.md     |  60 +++++
 .../sql-functions/array-functions/array_max.md     |  60 +++++
 .../sql-functions/array-functions/array_min.md     |  60 +++++
 .../sql-functions/array-functions/array_product.md |  60 +++++
 .../sql-functions/array-functions/array_sum.md     |  60 +++++
 .../java/org/apache/doris/catalog/ArrayType.java   |   4 +-
 .../main/java/org/apache/doris/catalog/Type.java   |   2 -
 gensrc/script/doris_builtins_functions.py          |  38 ++-
 27 files changed, 1494 insertions(+), 25 deletions(-)

diff --git a/be/src/vec/CMakeLists.txt b/be/src/vec/CMakeLists.txt
index fc50adca0a..6334a92a08 100644
--- a/be/src/vec/CMakeLists.txt
+++ b/be/src/vec/CMakeLists.txt
@@ -128,6 +128,7 @@ set(VEC_FILES
   functions/array/function_array_element.cpp
   functions/array/function_array_register.cpp
   functions/array/function_array_size.cpp
+  functions/array/function_array_aggregation.cpp
   exprs/table_function/vexplode_json_array.cpp
   functions/math.cpp
   functions/function_bitmap.cpp
diff --git a/be/src/vec/aggregate_functions/aggregate_function.h b/be/src/vec/aggregate_functions/aggregate_function.h
index d822dada79..eca81b3199 100644
--- a/be/src/vec/aggregate_functions/aggregate_function.h
+++ b/be/src/vec/aggregate_functions/aggregate_function.h
@@ -209,4 +209,21 @@ public:
 
 using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;
 
+class AggregateFunctionGuard {
+public:
+    using AggregateData = std::remove_pointer_t<AggregateDataPtr>;
+
+    explicit AggregateFunctionGuard(const IAggregateFunction* function)
+            : _function(function),
+              _data(std::make_unique<AggregateData[]>(function->size_of_data())) {
+        _function->create(_data.get());
+    };
+    ~AggregateFunctionGuard() { _function->destroy(_data.get()); }
+    AggregateDataPtr data() { return _data.get(); };
+
+private:
+    const IAggregateFunction* _function;
+    std::unique_ptr<AggregateData[]> _data;
+};
+
 } // namespace doris::vectorized
diff --git a/be/src/vec/aggregate_functions/aggregate_function_product.h b/be/src/vec/aggregate_functions/aggregate_function_product.h
new file mode 100644
index 0000000000..0e392b0e69
--- /dev/null
+++ b/be/src/vec/aggregate_functions/aggregate_function_product.h
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <cstddef>
+#include <type_traits>
+
+#include "vec/aggregate_functions/aggregate_function.h"
+#include "vec/columns/column_decimal.h"
+#include "vec/columns/column_vector.h"
+#include "vec/common/arena.h"
+#include "vec/common/string_buffer.hpp"
+#include "vec/core/types.h"
+#include "vec/data_types/data_type_decimal.h"
+#include "vec/data_types/data_type_number.h"
+#include "vec/io/io_helper.h"
+
+namespace doris {
+namespace vectorized {
+
+template <typename T>
+struct AggregateFunctionProductData {
+    T product {};
+
+    void add(T value) { product *= value; }
+
+    void merge(const AggregateFunctionProductData& other) { product *= other.product; }
+
+    void write(BufferWritable& buffer) const { write_binary(product, buffer); }
+
+    void read(BufferReadable& buffer) { read_binary(product, buffer); }
+
+    T get() const { return product; }
+
+    void reset(T value) { product = std::move(value); }
+};
+
+template <typename T, typename TResult, typename Data>
+class AggregateFunctionProduct final
+        : public IAggregateFunctionDataHelper<Data, AggregateFunctionProduct<T, TResult, Data>> {
+public:
+    using ResultDataType = std::conditional_t<IsDecimalNumber<T>, DataTypeDecimal<TResult>,
+                                              DataTypeNumber<TResult>>;
+    using ColVecType = std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<T>, ColumnVector<T>>;
+    using ColVecResult =
+            std::conditional_t<IsDecimalNumber<T>, ColumnDecimal<TResult>, ColumnVector<TResult>>;
+
+    std::string get_name() const { return "product"; }
+
+    AggregateFunctionProduct(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<Data, AggregateFunctionProduct<T, TResult, Data>>(
+                      argument_types_, {}),
+              scale(0) {}
+
+    AggregateFunctionProduct(const IDataType& data_type, const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<Data, AggregateFunctionProduct<T, TResult, Data>>(
+                      argument_types_, {}),
+              scale(get_decimal_scale(data_type)) {}
+
+    DataTypePtr get_return_type() const override {
+        if constexpr (IsDecimalNumber<T>) {
+            return std::make_shared<ResultDataType>(ResultDataType::max_precision(), scale);
+        } else {
+            return std::make_shared<ResultDataType>();
+        }
+    }
+
+    void add(AggregateDataPtr __restrict place, const IColumn** columns, size_t row_num,
+             Arena*) const override {
+        const auto& column = static_cast<const ColVecType&>(*columns[0]);
+        this->data(place).add(column.get_data()[row_num]);
+    }
+
+    void reset(AggregateDataPtr place) const override {
+        if constexpr (IsDecimalNumber<T>) {
+            this->data(place).reset(T(1 * ResultDataType::get_scale_multiplier(scale)));
+        } else {
+            this->data(place).reset(1);
+        }
+    }
+
+    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
+               Arena*) const override {
+        this->data(place).merge(this->data(rhs));
+    }
+
+    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
+        this->data(place).write(buf);
+    }
+
+    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
+                     Arena*) const override {
+        this->data(place).read(buf);
+    }
+
+    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
+        auto& column = static_cast<ColVecResult&>(to);
+        column.get_data().push_back(this->data(place).get());
+    }
+
+private:
+    UInt32 scale;
+};
+
+} // namespace vectorized
+} // namespace doris
diff --git a/be/src/vec/columns/column_decimal.h b/be/src/vec/columns/column_decimal.h
index 98c2d05ef4..dd93768e2f 100644
--- a/be/src/vec/columns/column_decimal.h
+++ b/be/src/vec/columns/column_decimal.h
@@ -21,6 +21,7 @@
 #pragma once
 
 #include <cmath>
+#include <type_traits>
 
 #include "olap/decimal12.h"
 #include "vec/columns/column.h"
@@ -204,6 +205,8 @@ public:
         data[self_row] = T();
     }
 
+    UInt32 get_scale() const { return scale; }
+
 protected:
     Container data;
     UInt32 scale;
@@ -226,6 +229,22 @@ protected:
     }
 };
 
+template <typename>
+class ColumnVector;
+
+template <typename T, bool is_decimal = false>
+struct ColumnVectorOrDecimalT {
+    using Col = ColumnVector<T>;
+};
+
+template <typename T>
+struct ColumnVectorOrDecimalT<T, true> {
+    using Col = ColumnDecimal<T>;
+};
+
+template <typename T>
+using ColumnVectorOrDecimal = typename ColumnVectorOrDecimalT<T, IsDecimalNumber<T>>::Col;
+
 template <typename T>
 template <typename Type>
 ColumnPtr ColumnDecimal<T>::index_impl(const PaddedPODArray<Type>& indexes, size_t limit) const {
diff --git a/be/src/vec/core/types.h b/be/src/vec/core/types.h
index f4ca212d0b..650b64a627 100644
--- a/be/src/vec/core/types.h
+++ b/be/src/vec/core/types.h
@@ -345,6 +345,13 @@ inline constexpr bool IsDecimalNumber<Decimal64> = true;
 template <>
 inline constexpr bool IsDecimalNumber<Decimal128> = true;
 
+template <typename T>
+constexpr bool IsFloatNumber = false;
+template <>
+inline constexpr bool IsFloatNumber<Float32> = true;
+template <>
+inline constexpr bool IsFloatNumber<Float64> = true;
+
 template <typename T>
 struct NativeType {
     using Type = T;
diff --git a/be/src/vec/functions/array/function_array_aggregation.cpp b/be/src/vec/functions/array/function_array_aggregation.cpp
new file mode 100644
index 0000000000..8095ff75ad
--- /dev/null
+++ b/be/src/vec/functions/array/function_array_aggregation.cpp
@@ -0,0 +1,287 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/array/arrayAggregation.cpp
+// and modified by Doris
+
+#include <type_traits>
+
+#include "vec/aggregate_functions/aggregate_function_avg.h"
+#include "vec/aggregate_functions/aggregate_function_min_max.h"
+#include "vec/aggregate_functions/aggregate_function_null.h"
+#include "vec/aggregate_functions/aggregate_function_product.h"
+#include "vec/aggregate_functions/aggregate_function_sum.h"
+#include "vec/aggregate_functions/helpers.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/common/arena.h"
+#include "vec/core/types.h"
+#include "vec/data_types/data_type.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/functions/array/function_array_mapped.h"
+#include "vec/functions/simple_function_factory.h"
+
+namespace doris {
+namespace vectorized {
+
+enum class AggregateOperation { MIN, MAX, SUM, AVERAGE, PRODUCT };
+
+template <typename Element, AggregateOperation operation>
+struct ArrayAggregateResultImpl;
+
+template <typename Element>
+struct ArrayAggregateResultImpl<Element, AggregateOperation::MIN> {
+    using Result = Element;
+};
+
+template <typename Element>
+struct ArrayAggregateResultImpl<Element, AggregateOperation::MAX> {
+    using Result = Element;
+};
+
+template <typename Element>
+struct ArrayAggregateResultImpl<Element, AggregateOperation::AVERAGE> {
+    using Result = std::conditional_t<IsDecimalNumber<Element>, Decimal128, Float64>;
+};
+
+template <typename Element>
+struct ArrayAggregateResultImpl<Element, AggregateOperation::PRODUCT> {
+    using Result = std::conditional_t<IsDecimalNumber<Element>, Decimal128, Float64>;
+};
+
+template <typename Element>
+struct ArrayAggregateResultImpl<Element, AggregateOperation::SUM> {
+    using Result = std::conditional_t<
+            IsDecimalNumber<Element>, Decimal128,
+            std::conditional_t<IsFloatNumber<Element>, Float64,
+                               std::conditional_t<std::is_same_v<Element, Int128>, Int128, Int64>>>;
+};
+
+template <typename Element, AggregateOperation operation>
+using ArrayAggregateResult = typename ArrayAggregateResultImpl<Element, operation>::Result;
+
+// For MIN/MAX, the type of result is the same as the type of elements, we can omit the
+// template specialization.
+template <AggregateOperation operation>
+struct AggregateFunctionImpl;
+
+template <>
+struct AggregateFunctionImpl<AggregateOperation::SUM> {
+    template <typename Element>
+    struct TypeTraits {
+        using ResultType = ArrayAggregateResult<Element, AggregateOperation::SUM>;
+        using AggregateDataType = AggregateFunctionSumData<ResultType>;
+        using Function = AggregateFunctionSum<Element, ResultType, AggregateDataType>;
+    };
+};
+
+template <>
+struct AggregateFunctionImpl<AggregateOperation::AVERAGE> {
+    template <typename Element>
+    struct TypeTraits {
+        using ResultType = ArrayAggregateResult<Element, AggregateOperation::AVERAGE>;
+        using AggregateDataType = AggregateFunctionAvgData<ResultType>;
+        using Function = AggregateFunctionAvg<Element, AggregateDataType>;
+        static_assert(std::is_same_v<ResultType, typename Function::ResultType>,
+                      "ResultType doesn't match.");
+    };
+};
+
+template <>
+struct AggregateFunctionImpl<AggregateOperation::PRODUCT> {
+    template <typename Element>
+    struct TypeTraits {
+        using ResultType = ArrayAggregateResult<Element, AggregateOperation::PRODUCT>;
+        using AggregateDataType = AggregateFunctionProductData<Element>;
+        using Function = AggregateFunctionProduct<Element, ResultType, AggregateDataType>;
+    };
+};
+
+template <typename Derived>
+struct AggregateFunction {
+    template <typename T>
+    using Function = typename Derived::template TypeTraits<T>::Function;
+
+    static auto create(const DataTypePtr& data_type_ptr) -> AggregateFunctionPtr {
+        DataTypes data_types = {remove_nullable(data_type_ptr)};
+        auto& data_type = *data_types.front();
+        AggregateFunctionPtr nested_function;
+        if (is_decimal(data_types.front())) {
+            nested_function = AggregateFunctionPtr(
+                    create_with_decimal_type<Function>(data_type, data_type, data_types));
+        } else {
+            nested_function =
+                    AggregateFunctionPtr(create_with_numeric_type<Function>(data_type, data_types));
+        }
+
+        AggregateFunctionPtr function;
+        function.reset(new AggregateFunctionNullUnary<true>(nested_function,
+                                                            {make_nullable(data_type_ptr)}, {}));
+        return function;
+    }
+};
+
+template <AggregateOperation operation>
+struct ArrayAggregateImpl {
+    using column_type = ColumnArray;
+    using data_type = DataTypeArray;
+
+    static DataTypePtr get_return_type(const DataTypeArray* data_type_array) {
+        using Function = AggregateFunction<AggregateFunctionImpl<operation>>;
+        auto function = Function::create(data_type_array->get_nested_type());
+        return function->get_return_type();
+    }
+
+    static Status execute(Block& block, size_t result, const DataTypeArray* data_type_array,
+                          const ColumnArray& array) {
+        ColumnPtr res;
+        DataTypePtr type = data_type_array->get_nested_type();
+        const IColumn* data = array.get_data_ptr().get();
+
+        const auto& offsets = array.get_offsets();
+        if (execute_type<Int8>(res, type, data, offsets) ||
+            execute_type<Int16>(res, type, data, offsets) ||
+            execute_type<Int32>(res, type, data, offsets) ||
+            execute_type<Int64>(res, type, data, offsets) ||
+            execute_type<Int128>(res, type, data, offsets) ||
+            execute_type<Float32>(res, type, data, offsets) ||
+            execute_type<Float64>(res, type, data, offsets) ||
+            execute_type<Decimal128>(res, type, data, offsets)) {
+            block.replace_by_position(result, std::move(res));
+            return Status::OK();
+        } else {
+            return Status::RuntimeError("Unexpected column for aggregation: " + data->get_name());
+        }
+    }
+
+    template <typename Element>
+    static bool execute_type(ColumnPtr& res_ptr, const DataTypePtr& type, const IColumn* data,
+                             const ColumnArray::Offsets& offsets) {
+        using ColVecType = ColumnVectorOrDecimal<Element>;
+        using ResultType = ArrayAggregateResult<Element, operation>;
+        using ColVecResultType = ColumnVectorOrDecimal<ResultType>;
+        using Function = AggregateFunction<AggregateFunctionImpl<operation>>;
+
+        const ColVecType* column =
+                data->is_nullable()
+                        ? check_and_get_column<ColVecType>(
+                                  static_cast<const ColumnNullable*>(data)->get_nested_column())
+                        : check_and_get_column<ColVecType>(&*data);
+        if (!column) {
+            return false;
+        }
+
+        ColumnPtr res_column;
+        if constexpr (IsDecimalNumber<Element>) {
+            res_column = ColVecResultType::create(0, column->get_scale());
+        } else {
+            res_column = ColVecResultType::create();
+        }
+        res_column = make_nullable(res_column);
+        static_cast<ColumnNullable&>(res_column->assume_mutable_ref()).reserve(offsets.size());
+
+        auto function = Function::create(type);
+        auto guard = AggregateFunctionGuard(function.get());
+        Arena arena;
+        auto nullable_column = make_nullable(data->get_ptr());
+        const IColumn* columns[] = {nullable_column.get()};
+        for (int64_t i = 0; i < offsets.size(); ++i) {
+            auto start = offsets[i - 1]; // -1 is ok.
+            auto end = offsets[i];
+            bool is_empty = (start == end);
+            if (is_empty) {
+                res_column->assume_mutable()->insert_default();
+                continue;
+            }
+            function->reset(guard.data());
+            function->add_batch_range(start, end - 1, guard.data(), columns, &arena,
+                                      data->is_nullable());
+            function->insert_result_into(guard.data(), res_column->assume_mutable_ref());
+        }
+        res_ptr = std::move(res_column);
+        return true;
+    };
+};
+
+struct NameArrayMin {
+    static constexpr auto name = "array_min";
+};
+
+template <>
+struct AggregateFunction<AggregateFunctionImpl<AggregateOperation::MIN>> {
+    static auto create(const DataTypePtr& data_type_ptr) -> AggregateFunctionPtr {
+        DataTypes data_types = {remove_nullable(data_type_ptr)};
+        auto nested_function = AggregateFunctionPtr(
+                create_aggregate_function_min(NameArrayMin::name, data_types, {}, false));
+
+        AggregateFunctionPtr function;
+        function.reset(new AggregateFunctionNullUnary<true>(nested_function,
+                                                            {make_nullable(data_type_ptr)}, {}));
+        return function;
+    }
+};
+
+struct NameArrayMax {
+    static constexpr auto name = "array_max";
+};
+
+template <>
+struct AggregateFunction<AggregateFunctionImpl<AggregateOperation::MAX>> {
+    static auto create(const DataTypePtr& data_type_ptr) -> AggregateFunctionPtr {
+        DataTypes data_types = {remove_nullable(data_type_ptr)};
+        auto nested_function = AggregateFunctionPtr(
+                create_aggregate_function_max(NameArrayMax::name, data_types, {}, false));
+
+        AggregateFunctionPtr function;
+        function.reset(new AggregateFunctionNullUnary<true>(nested_function,
+                                                            {make_nullable(data_type_ptr)}, {}));
+        return function;
+    }
+};
+
+struct NameArraySum {
+    static constexpr auto name = "array_sum";
+};
+
+struct NameArrayAverage {
+    static constexpr auto name = "array_avg";
+};
+
+struct NameArrayProduct {
+    static constexpr auto name = "array_product";
+};
+
+using FunctionArrayMin =
+        FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::MIN>, NameArrayMin>;
+using FunctionArrayMax =
+        FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::MAX>, NameArrayMax>;
+using FunctionArraySum =
+        FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::SUM>, NameArraySum>;
+using FunctionArrayAverage =
+        FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::AVERAGE>, NameArrayAverage>;
+using FunctionArrayProduct =
+        FunctionArrayMapped<ArrayAggregateImpl<AggregateOperation::PRODUCT>, NameArrayProduct>;
+
+void register_function_array_aggregation(SimpleFunctionFactory& factory) {
+    factory.register_function<FunctionArrayMin>();
+    factory.register_function<FunctionArrayMax>();
+    factory.register_function<FunctionArraySum>();
+    factory.register_function<FunctionArrayAverage>();
+    factory.register_function<FunctionArrayProduct>();
+}
+
+} // namespace vectorized
+} // namespace doris
diff --git a/be/src/vec/functions/array/function_array_mapped.h b/be/src/vec/functions/array/function_array_mapped.h
new file mode 100644
index 0000000000..6a38993fb4
--- /dev/null
+++ b/be/src/vec/functions/array/function_array_mapped.h
@@ -0,0 +1,76 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+// This file is copied from
+// https://github.com/ClickHouse/ClickHouse/blob/master/src/Functions/array/FunctionArrayMapped.h
+// and modified by Doris
+
+#include "vec/columns/column.h"
+#include "vec/columns/column_nullable.h"
+#include "vec/data_types/data_type_array.h"
+#include "vec/data_types/data_type_nullable.h"
+#include "vec/functions/function.h"
+
+namespace doris {
+namespace vectorized {
+
+/** Higher-order functions for arrays.
+  * These functions optionally apply a map (transform) to array (or multiple arrays of identical size) by lambda function,
+  *  and return some result based on that transformation.
+  *
+  * Examples:
+  * arrayMap(x1,...,xn -> expression, array1,...,arrayn) - apply the expression to each element of the array (or set of parallel arrays).
+  * arrayFilter(x -> predicate, array) - leave in the array only the elements for which the expression is true.
+  *
+  * For some functions arrayCount, arrayExists, arrayAll, an overload of the form f(array) is available,
+  *  which works in the same way as f(x -> x, array).
+  *
+  * See the example of Impl template parameter in arrayMap.cpp
+  */
+template <typename Impl, typename Name>
+class FunctionArrayMapped : public IFunction {
+public:
+    static constexpr auto name = Name::name;
+    static FunctionPtr create() { return std::make_shared<FunctionArrayMapped>(); }
+
+    String get_name() const override { return name; }
+    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
+                        size_t result, size_t input_rows_count) override {
+        const auto& typed_column = block.get_by_position(arguments[0]);
+        const typename Impl::column_type* column_array;
+        if (typed_column.column->is_nullable()) {
+            column_array = check_and_get_column<const typename Impl::column_type>(
+                    static_cast<const ColumnNullable*>(typed_column.column.get())
+                            ->get_nested_column_ptr()
+                            .get());
+        } else {
+            column_array = check_and_get_column<const typename Impl::column_type>(
+                    typed_column.column.get());
+        }
+        const auto* data_type_array =
+                static_cast<const DataTypeArray*>(remove_nullable(typed_column.type).get());
+        return Impl::execute(block, result, data_type_array, *column_array);
+    }
+    size_t get_number_of_arguments() const override { return 1; }
+    DataTypePtr get_return_type_impl(const DataTypes& arguments) const override {
+        const DataTypeArray* data_type_array =
+                static_cast<const DataTypeArray*>(remove_nullable(arguments[0]).get());
+        return Impl::get_return_type(data_type_array);
+    }
+};
+
+} // namespace vectorized
+} // namespace doris
diff --git a/be/src/vec/functions/array/function_array_register.cpp b/be/src/vec/functions/array/function_array_register.cpp
index 3c5dc4fd19..833bc9fbd8 100644
--- a/be/src/vec/functions/array/function_array_register.cpp
+++ b/be/src/vec/functions/array/function_array_register.cpp
@@ -25,11 +25,13 @@ namespace doris::vectorized {
 void register_function_array_element(SimpleFunctionFactory&);
 void register_function_array_index(SimpleFunctionFactory&);
 void register_function_array_size(SimpleFunctionFactory&);
+void register_function_array_aggregation(SimpleFunctionFactory&);
 
 void register_function_array(SimpleFunctionFactory& factory) {
     register_function_array_element(factory);
     register_function_array_index(factory);
     register_function_array_size(factory);
+    register_function_array_aggregation(factory);
 }
 
 } // namespace doris::vectorized
diff --git a/be/src/vec/functions/function.h b/be/src/vec/functions/function.h
index 802ef6fdf4..c4464e4956 100644
--- a/be/src/vec/functions/function.h
+++ b/be/src/vec/functions/function.h
@@ -25,7 +25,6 @@
 #include "common/status.h"
 #include "vec/core/block.h"
 #include "vec/core/column_numbers.h"
-#include "vec/core/names.h"
 #include "vec/data_types/data_type.h"
 
 namespace doris::vectorized {
diff --git a/be/src/vec/functions/simple_function_factory.h b/be/src/vec/functions/simple_function_factory.h
index 7e56dbac99..32042095ff 100644
--- a/be/src/vec/functions/simple_function_factory.h
+++ b/be/src/vec/functions/simple_function_factory.h
@@ -80,6 +80,7 @@ void register_function_geo(SimpleFunctionFactory& factory);
 void register_function_encryption(SimpleFunctionFactory& factory);
 void register_function_regexp_extract(SimpleFunctionFactory& factory);
 void register_function_hex_variadic(SimpleFunctionFactory& factory);
+
 class SimpleFunctionFactory {
     using Creator = std::function<FunctionBuilderPtr()>;
     using FunctionCreators = phmap::flat_hash_map<std::string, Creator>;
@@ -161,7 +162,7 @@ public:
     static SimpleFunctionFactory& instance() {
         static std::once_flag oc;
         static SimpleFunctionFactory instance;
-        std::call_once(oc, [&]() {
+        std::call_once(oc, []() {
             register_function_bitmap(instance);
             register_function_bitmap_variadic(instance);
             register_function_hll_cardinality(instance);
diff --git a/be/test/CMakeLists.txt b/be/test/CMakeLists.txt
index dabd56304e..8928363ec6 100644
--- a/be/test/CMakeLists.txt
+++ b/be/test/CMakeLists.txt
@@ -336,6 +336,7 @@ set(VEC_TEST_FILES
     vec/exec/vorc_scanner_test.cpp
     vec/exec/vparquet_scanner_test.cpp
     vec/exprs/vexpr_test.cpp
+    vec/function/function_array_aggregation_test.cpp
     vec/function/function_array_element_test.cpp
     vec/function/function_array_index_test.cpp
     vec/function/function_array_size_test.cpp
diff --git a/be/test/vec/function/function_array_aggregation_test.cpp b/be/test/vec/function/function_array_aggregation_test.cpp
new file mode 100644
index 0000000000..54f8eaa945
--- /dev/null
+++ b/be/test/vec/function/function_array_aggregation_test.cpp
@@ -0,0 +1,228 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gtest/gtest.h>
+
+#include <cstddef>
+#include <string>
+#include <type_traits>
+
+#include "function_test_util.h"
+#include "vec/core/field.h"
+#include "vec/data_types/data_type_number.h"
+
+namespace doris {
+namespace vectorized {
+
+template <typename T>
+struct AnyValue {
+    T value {};
+    bool is_null = false;
+
+    AnyValue(T v) : value(std::move(v)) {}
+
+    AnyValue(std::nullptr_t) : is_null(true) {}
+};
+
+using IntDataSet = std::vector<std::pair<std::vector<AnyValue<int>>, AnyValue<int>>>;
+
+template <typename T, typename ReturnType = T>
+void check_function(const std::string& func_name, const IntDataSet data_set,
+                    bool nullable = false) {
+    InputTypeSet input_types;
+    if (!nullable) {
+        input_types = {TypeIndex::Array, ut_type::get_type_index<T>()};
+    } else {
+        input_types = {TypeIndex::Array, TypeIndex::Nullable, ut_type::get_type_index<T>()};
+    }
+    DataSet converted_data_set;
+    for (const auto& row : data_set) {
+        Array array;
+        for (auto any_value : row.first) {
+            if (any_value.is_null) {
+                array.push_back(Field());
+            } else {
+                array.push_back(ut_type::convert_to<T>(any_value.value));
+            }
+        }
+        if (!row.second.is_null) {
+            converted_data_set.emplace_back(std::make_pair<CellSet, Expect>(
+                    {array}, ut_type::convert_to<ReturnType>(row.second.value)));
+        } else {
+            converted_data_set.emplace_back(std::make_pair<CellSet, Expect>({array}, Null()));
+        }
+    }
+    check_function<ReturnType, true>(func_name, input_types, converted_data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayMin) {
+    const std::string func_name = "array_min";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{1, 2, 3}, 1},
+    };
+    check_function<DataTypeInt8>(func_name, data_set);
+    check_function<DataTypeInt16>(func_name, data_set);
+    check_function<DataTypeInt32>(func_name, data_set);
+    check_function<DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt128>(func_name, data_set);
+    check_function<DataTypeFloat32>(func_name, data_set);
+    check_function<DataTypeFloat64>(func_name, data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayMinNullable) {
+    const std::string func_name = "array_min";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{nullptr}, nullptr},
+            {{1, nullptr, 3}, 1},
+    };
+    check_function<DataTypeInt8>(func_name, data_set, true);
+    check_function<DataTypeInt16>(func_name, data_set, true);
+    check_function<DataTypeInt32>(func_name, data_set, true);
+    check_function<DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt128>(func_name, data_set, true);
+    check_function<DataTypeFloat32>(func_name, data_set, true);
+    check_function<DataTypeFloat64>(func_name, data_set, true);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayMax) {
+    const std::string func_name = "array_max";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{1, 2, 3}, 3},
+    };
+    check_function<DataTypeInt8>(func_name, data_set);
+    check_function<DataTypeInt16>(func_name, data_set);
+    check_function<DataTypeInt32>(func_name, data_set);
+    check_function<DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt128>(func_name, data_set);
+    check_function<DataTypeFloat32>(func_name, data_set);
+    check_function<DataTypeFloat64>(func_name, data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayMaxNullable) {
+    const std::string func_name = "array_max";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{nullptr}, nullptr},
+            {{1, nullptr, 3}, 3},
+    };
+    check_function<DataTypeInt8>(func_name, data_set, true);
+    check_function<DataTypeInt16>(func_name, data_set, true);
+    check_function<DataTypeInt32>(func_name, data_set, true);
+    check_function<DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt128>(func_name, data_set, true);
+    check_function<DataTypeFloat32>(func_name, data_set, true);
+    check_function<DataTypeFloat64>(func_name, data_set, true);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArraySum) {
+    const std::string func_name = "array_sum";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{1, 2, 3}, 6},
+    };
+    check_function<DataTypeInt8, DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt16, DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt32, DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt64, DataTypeInt64>(func_name, data_set);
+    check_function<DataTypeInt128, DataTypeInt128>(func_name, data_set);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArraySumNullable) {
+    const std::string func_name = "array_sum";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{nullptr}, nullptr},
+            {{1, nullptr, 3}, 4},
+    };
+    check_function<DataTypeInt8, DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt16, DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt32, DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt64, DataTypeInt64>(func_name, data_set, true);
+    check_function<DataTypeInt128, DataTypeInt128>(func_name, data_set, true);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set, true);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayAverage) {
+    const std::string func_name = "array_avg";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{1, 2, 3}, 2},
+    };
+    check_function<DataTypeInt8, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt16, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt32, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt64, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt128, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayAverageNullable) {
+    const std::string func_name = "array_avg";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{nullptr}, nullptr},
+            {{1, nullptr, 3}, 2},
+    };
+    check_function<DataTypeInt8, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt16, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt32, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt64, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt128, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set, true);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayProduct) {
+    const std::string func_name = "array_product";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{1, 2, 3}, 6},
+    };
+    check_function<DataTypeInt8, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt16, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt32, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt64, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeInt128, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set);
+}
+
+TEST(VFunctionArrayAggregationTest, TestArrayProductNullable) {
+    const std::string func_name = "array_product";
+    IntDataSet data_set = {
+            {{}, nullptr},
+            {{nullptr}, nullptr},
+            {{1, nullptr, 3}, 3},
+    };
+    check_function<DataTypeInt8, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt16, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt32, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt64, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeInt128, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeFloat32, DataTypeFloat64>(func_name, data_set, true);
+    check_function<DataTypeFloat64, DataTypeFloat64>(func_name, data_set, true);
+}
+
+} // namespace vectorized
+} // namespace doris
diff --git a/be/test/vec/function/function_test_util.cpp b/be/test/vec/function/function_test_util.cpp
index 9587805b21..0e25aa1781 100644
--- a/be/test/vec/function/function_test_util.cpp
+++ b/be/test/vec/function/function_test_util.cpp
@@ -33,7 +33,8 @@ int64_t str_to_date_time(std::string datetime_str, bool data_time) {
     return binary_cast<VecDateTimeValue, Int64>(v);
 }
 size_t type_index_to_data_type(const std::vector<std::any>& input_types, size_t index,
-                               doris_udf::FunctionContext::TypeDesc& desc, DataTypePtr& type) {
+                               ut_type::UTDataTypeDesc& ut_desc, DataTypePtr& type) {
+    doris_udf::FunctionContext::TypeDesc& desc = ut_desc.type_desc;
     if (index < 0 || index >= input_types.size()) {
         return -1;
     }
@@ -96,14 +97,25 @@ size_t type_index_to_data_type(const std::vector<std::any>& input_types, size_t
         return 1;
     case TypeIndex::Array: {
         desc.type = doris_udf::FunctionContext::TYPE_ARRAY;
-        doris_udf::FunctionContext::TypeDesc sub_desc;
+        ut_type::UTDataTypeDesc sub_desc;
         DataTypePtr sub_type = nullptr;
-        size_t ret = type_index_to_data_type(input_types, index + 1, sub_desc, sub_type);
+        ++index;
+        size_t ret = type_index_to_data_type(input_types, index, sub_desc, sub_type);
         if (ret <= 0) {
             return ret;
         }
-        desc.children.push_back(doris_udf::FunctionContext::TypeDesc());
-        type = std::make_shared<DataTypeArray>(std::move(sub_type));
+        desc.children.push_back(sub_desc.type_desc);
+        type = std::make_shared<DataTypeArray>(sub_type);
+        return ret + 1;
+    }
+    case TypeIndex::Nullable: {
+        ++index;
+        size_t ret = type_index_to_data_type(input_types, index, ut_desc, type);
+        if (ret <= 0) {
+            return ret;
+        }
+        ut_desc.is_nullable = true;
+        type = make_nullable(type);
         return ret + 1;
     }
     default:
@@ -119,7 +131,7 @@ bool parse_ut_data_type(const std::vector<std::any>& input_types, ut_type::UTDat
         if (input_types[i].type() == typeid(Consted)) {
             desc.is_const = true;
         }
-        size_t res = type_index_to_data_type(input_types, i, desc.type_desc, desc.data_type);
+        size_t res = type_index_to_data_type(input_types, i, desc, desc.data_type);
         if (res <= 0) {
             return false;
         }
diff --git a/be/test/vec/function/function_test_util.h b/be/test/vec/function/function_test_util.h
index 42ba1185b7..6ad30a9b6a 100644
--- a/be/test/vec/function/function_test_util.h
+++ b/be/test/vec/function/function_test_util.h
@@ -38,7 +38,10 @@
 namespace doris::vectorized {
 
 using InputDataSet = std::vector<std::vector<std::any>>; // without result
-using DataSet = std::vector<std::pair<std::vector<std::any>, std::any>>;
+using CellSet = std::vector<std::any>;
+using Expect = std::any;
+using Row = std::pair<CellSet, Expect>;
+using DataSet = std::vector<Row>;
 using InputTypeSet = std::vector<std::any>;
 
 int64_t str_to_date_time(std::string datetime_str, bool data_time = true);
@@ -64,6 +67,69 @@ inline auto DECIMALFIELD = [](double v) {
 
 using DATETIME = std::string;
 
+template <typename T>
+struct DataTypeTraits;
+
+template <>
+struct DataTypeTraits<DataTypeInt8> {
+    using type = Int8;
+};
+
+template <>
+struct DataTypeTraits<DataTypeInt16> {
+    using type = Int16;
+};
+
+template <>
+struct DataTypeTraits<DataTypeInt32> {
+    using type = Int32;
+};
+
+template <>
+struct DataTypeTraits<DataTypeInt64> {
+    using type = Int64;
+};
+
+template <>
+struct DataTypeTraits<DataTypeInt128> {
+    using type = Int128;
+};
+
+template <>
+struct DataTypeTraits<DataTypeFloat32> {
+    using type = Float32;
+};
+
+template <>
+struct DataTypeTraits<DataTypeFloat64> {
+    using type = Float64;
+};
+
+template <typename To, typename From>
+constexpr decltype(auto) convert_to(From value) {
+    using ToType = typename DataTypeTraits<To>::type;
+    return ToType(value);
+}
+
+template <typename T>
+constexpr TypeIndex get_type_index() {
+    if constexpr (std::is_same_v<T, DataTypeInt8>) {
+        return TypeIndex::Int8;
+    } else if constexpr (std::is_same_v<T, DataTypeInt16>) {
+        return TypeIndex::Int16;
+    } else if constexpr (std::is_same_v<T, DataTypeInt32>) {
+        return TypeIndex::Int32;
+    } else if constexpr (std::is_same_v<T, DataTypeInt64>) {
+        return TypeIndex::Int64;
+    } else if constexpr (std::is_same_v<T, DataTypeInt128>) {
+        return TypeIndex::Int128;
+    } else if constexpr (std::is_same_v<T, DataTypeFloat32>) {
+        return TypeIndex::Float32;
+    } else if constexpr (std::is_same_v<T, DataTypeFloat64>) {
+        return TypeIndex::Float64;
+    }
+}
+
 struct UTDataTypeDesc {
     DataTypePtr data_type;
     doris_udf::FunctionContext::TypeDesc type_desc;
@@ -76,7 +142,7 @@ using UTDataTypeDescs = std::vector<UTDataTypeDesc>;
 } // namespace ut_type
 
 size_t type_index_to_data_type(const std::vector<std::any>& input_types, size_t index,
-                               doris_udf::FunctionContext::TypeDesc& desc, DataTypePtr& type);
+                               ut_type::UTDataTypeDesc& ut_desc, DataTypePtr& type);
 bool parse_ut_data_type(const std::vector<std::any>& input_types, ut_type::UTDataTypeDescs& descs);
 
 bool insert_cell(MutableColumnPtr& column, DataTypePtr type_ptr, const std::any& cell);
@@ -146,13 +212,13 @@ void check_function(const std::string& func_name, const InputTypeSet& input_type
     EXPECT_TRUE(func != nullptr);
 
     doris_udf::FunctionContext::TypeDesc fn_ctx_return;
-    if (std::is_same_v<ReturnType, DataTypeUInt8>) {
+    if constexpr (std::is_same_v<ReturnType, DataTypeUInt8>) {
         fn_ctx_return.type = doris_udf::FunctionContext::TYPE_BOOLEAN;
-    } else if (std::is_same_v<ReturnType, DataTypeFloat64>) {
-        fn_ctx_return.type = doris_udf::FunctionContext::TYPE_DOUBLE;
-    } else if (std::is_same_v<ReturnType, DataTypeInt32>) {
+    } else if constexpr (std::is_same_v<ReturnType, DataTypeInt32>) {
         fn_ctx_return.type = doris_udf::FunctionContext::TYPE_INT;
-    } else if (std::is_same_v<ReturnType, DateTime>) {
+    } else if constexpr (std::is_same_v<ReturnType, DataTypeFloat64>) {
+        fn_ctx_return.type = doris_udf::FunctionContext::TYPE_DOUBLE;
+    } else if constexpr (std::is_same_v<ReturnType, DateTime>) {
         fn_ctx_return.type = doris_udf::FunctionContext::TYPE_DATETIME;
     } else {
         fn_ctx_return.type = doris_udf::FunctionContext::INVALID_TYPE;
@@ -187,6 +253,9 @@ void check_function(const std::string& func_name, const InputTypeSet& input_type
             if constexpr (std::is_same_v<ReturnType, DataTypeDecimal<Decimal128>>) {
                 const auto& column_data = field.get<DecimalField<Decimal128>>().get_value();
                 EXPECT_EQ(column_data.value, expect_data.value);
+            } else if constexpr (std::is_same_v<ReturnType, DataTypeFloat32>) {
+                const auto& column_data = field.get<DataTypeFloat64::FieldType>();
+                EXPECT_EQ(column_data, expect_data);
             } else {
                 const auto& column_data = field.get<typename ReturnType::FieldType>();
                 EXPECT_EQ(column_data, expect_data);
diff --git a/docs/en/sql-manual/sql-functions/array-functions/array_avg.md b/docs/en/sql-manual/sql-functions/array-functions/array_avg.md
new file mode 100644
index 0000000000..0b47f51461
--- /dev/null
+++ b/docs/en/sql-manual/sql-functions/array-functions/array_avg.md
@@ -0,0 +1,61 @@
+---
+{
+    "title": "ARRAY_AVG Function",
+    "language": "en"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_AVG
+
+### Name
+
+ARRAY_AVG
+
+### description
+
+Get the average of all elements in an array (`NULL` values are skipped).
+When the array is empty or all elements in the array are `NULL` values, the function returns `NULL`.
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_avg(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_avg(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               2 |
+| [1, NULL, 3] |               2 |
++--------------+-----------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_AVG
+
diff --git a/docs/en/sql-manual/sql-functions/array-functions/array_max.md b/docs/en/sql-manual/sql-functions/array-functions/array_max.md
new file mode 100644
index 0000000000..68dafcf2b3
--- /dev/null
+++ b/docs/en/sql-manual/sql-functions/array-functions/array_max.md
@@ -0,0 +1,61 @@
+---
+{
+    "title": "ARRAY_MAX Function",
+    "language": "en"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_MAX
+
+### Name
+
+ARRAY_MAX
+
+### description
+
+Get the maximum element in an array (`NULL` values are skipped).
+When the array is empty or all elements in the array are `NULL` values, the function returns `NULL`.
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_max(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_max(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               3 |
+| [1, NULL, 3] |               3 |
++--------------+-----------------+
+4 rows in set (0.02 sec)
+
+```
+
+### keywords
+
+ARRAY_MAX
+
diff --git a/docs/en/sql-manual/sql-functions/array-functions/array_min.md b/docs/en/sql-manual/sql-functions/array-functions/array_min.md
new file mode 100644
index 0000000000..935992f26f
--- /dev/null
+++ b/docs/en/sql-manual/sql-functions/array-functions/array_min.md
@@ -0,0 +1,61 @@
+---
+{
+    "title": "ARRAY_MIN Function",
+    "language": "en"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_MIN
+
+### Name
+
+ARRAY_MIN
+
+### description
+
+Get the minimum element in an array (`NULL` values are skipped).
+When the array is empty or all elements in the array are `NULL` values, the function returns `NULL`.
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_min(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_min(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               1 |
+| [1, NULL, 3] |               1 |
++--------------+-----------------+
+4 rows in set (0.02 sec)
+
+```
+
+### keywords
+
+ARRAY_MIN
+
diff --git a/docs/en/sql-manual/sql-functions/array-functions/array_product.md b/docs/en/sql-manual/sql-functions/array-functions/array_product.md
new file mode 100644
index 0000000000..18c9896dd0
--- /dev/null
+++ b/docs/en/sql-manual/sql-functions/array-functions/array_product.md
@@ -0,0 +1,61 @@
+---
+{
+    "title": "ARRAY_PRODUCT Function",
+    "language": "en"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_PRODUCT
+
+### Name
+
+ARRAY_PRODUCT
+
+### description
+
+Get the product of all elements in an array (`NULL` values are skipped).
+When the array is empty or all elements in the array are `NULL` values, the function returns `NULL`.
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_product(k2) from array_type_table;
++--------------+---------------------+
+| k2           | array_product(`k2`) |
++--------------+---------------------+
+| []           |                NULL |
+| [NULL]       |                NULL |
+| [1, 2, 3]    |                   6 |
+| [1, NULL, 3] |                   3 |
++--------------+---------------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_PRODUCT
+
diff --git a/docs/en/sql-manual/sql-functions/array-functions/array_sum.md b/docs/en/sql-manual/sql-functions/array-functions/array_sum.md
new file mode 100644
index 0000000000..af0316bbcc
--- /dev/null
+++ b/docs/en/sql-manual/sql-functions/array-functions/array_sum.md
@@ -0,0 +1,61 @@
+---
+{
+    "title": "ARRAY_SUM Function",
+    "language": "en"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_SUM
+
+### Name
+
+ARRAY_SUM
+
+### description
+
+Get the sum of all elements in an array (`NULL` values are skipped).
+When the array is empty or all elements in the array are `NULL` values, the function returns `NULL`.
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_sum(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_sum(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               6 |
+| [1, NULL, 3] |               4 |
++--------------+-----------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_SUM
+
diff --git a/docs/zh-CN/sql-manual/sql-functions/array-functions/array_avg.md b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_avg.md
new file mode 100644
index 0000000000..39ab60fe18
--- /dev/null
+++ b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_avg.md
@@ -0,0 +1,60 @@
+---
+{
+    "title": "ARRAY_AVG 函数",
+    "language": "zh-CN"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_AVG
+
+### Name
+
+ARRAY_AVG
+
+### description
+
+返回数组中所有元素的平均值,数组中的`NULL`值会被跳过。空数组以及元素全为`NULL`值的数组,结果返回`NULL`值。
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_avg(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_avg(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               2 |
+| [1, NULL, 3] |               2 |
++--------------+-----------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_AVG
+
diff --git a/docs/zh-CN/sql-manual/sql-functions/array-functions/array_max.md b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_max.md
new file mode 100644
index 0000000000..c112eda8d9
--- /dev/null
+++ b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_max.md
@@ -0,0 +1,60 @@
+---
+{
+    "title": "ARRAY_MAX 函数",
+    "language": "zh-CN"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_MAX
+
+### Name
+
+ARRAY_MAX
+
+### description
+
+返回数组中最大的元素,数组中的`NULL`值会被跳过。空数组以及元素全为`NULL`值的数组,结果返回`NULL`值。
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_max(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_max(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               3 |
+| [1, NULL, 3] |               3 |
++--------------+-----------------+
+4 rows in set (0.02 sec)
+
+```
+
+### keywords
+
+ARRAY_MAX
+
diff --git a/docs/zh-CN/sql-manual/sql-functions/array-functions/array_min.md b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_min.md
new file mode 100644
index 0000000000..1681d681f5
--- /dev/null
+++ b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_min.md
@@ -0,0 +1,60 @@
+---
+{
+    "title": "ARRAY_MIN 函数",
+    "language": "zh-CN"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_MIN
+
+### Name
+
+ARRAY_MIN
+
+### description
+
+返回数组中最小的元素,数组中的`NULL`值会被跳过。空数组以及元素全为`NULL`值的数组,结果返回`NULL`值。
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_min(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_min(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               1 |
+| [1, NULL, 3] |               1 |
++--------------+-----------------+
+4 rows in set (0.02 sec)
+
+```
+
+### keywords
+
+ARRAY_MIN
+
diff --git a/docs/zh-CN/sql-manual/sql-functions/array-functions/array_product.md b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_product.md
new file mode 100644
index 0000000000..a2e5e510a3
--- /dev/null
+++ b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_product.md
@@ -0,0 +1,60 @@
+---
+{
+    "title": "ARRAY_PRODUCT 函数",
+    "language": "zh-CN"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_PRODUCT
+
+### Name
+
+ARRAY_PRODUCT
+
+### description
+
+返回数组中所有元素的乘积,数组中的`NULL`值会被跳过。空数组以及元素全为`NULL`值的数组,结果返回`NULL`值。
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_product(k2) from array_type_table;
++--------------+---------------------+
+| k2           | array_product(`k2`) |
++--------------+---------------------+
+| []           |                NULL |
+| [NULL]       |                NULL |
+| [1, 2, 3]    |                   6 |
+| [1, NULL, 3] |                   3 |
++--------------+---------------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_PRODUCT
+
diff --git a/docs/zh-CN/sql-manual/sql-functions/array-functions/array_sum.md b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_sum.md
new file mode 100644
index 0000000000..c84b83261c
--- /dev/null
+++ b/docs/zh-CN/sql-manual/sql-functions/array-functions/array_sum.md
@@ -0,0 +1,60 @@
+---
+{
+    "title": "ARRAY_SUM 函数",
+    "language": "zh-CN"
+}
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+## ARRAY_SUM
+
+### Name
+
+ARRAY_SUM
+
+### description
+
+返回数组中所有元素之和,数组中的`NULL`值会被跳过。空数组以及元素全为`NULL`值的数组,结果返回`NULL`值。
+
+### example
+
+```shell
+mysql> create table array_type_table(k1 INT, k2 Array<int>) duplicate key (k1)
+    -> distributed by hash(k1) buckets 1 properties('replication_num' = '1');
+mysql> insert into array_type_table values (0, []), (1, [NULL]), (2, [1, 2, 3]), (3, [1, NULL, 3]);
+mysql> set enable_vectorized_engine = true;    # enable vectorized engine
+mysql> select k2, array_sum(k2) from array_type_table;
++--------------+-----------------+
+| k2           | array_sum(`k2`) |
++--------------+-----------------+
+| []           |            NULL |
+| [NULL]       |            NULL |
+| [1, 2, 3]    |               6 |
+| [1, NULL, 3] |               4 |
++--------------+-----------------+
+4 rows in set (0.01 sec)
+
+```
+
+### keywords
+
+ARRAY_SUM
+
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java
index 4748d4cad9..8ad8bb9935 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/ArrayType.java
@@ -81,8 +81,8 @@ public class ArrayType extends Type {
         if (itemType.isNull() || ((ArrayType) t).getItemType().isNull()) {
             return true;
         }
-        return itemType.matchesType(((ArrayType) t).itemType)
-                && ((ArrayType) t).containsNull == containsNull;
+        return Type.isImplicitlyCastable(itemType, ((ArrayType) t).itemType, true)
+                && (((ArrayType) t).containsNull || !containsNull);
     }
 
     public static ArrayType create() {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Type.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Type.java
index 0ffbcdd37a..8a89b0ffe3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Type.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Type.java
@@ -401,8 +401,6 @@ public abstract class Type {
         }
         if (t1.isComplexType() || t2.isComplexType()) {
             if (t1.isArrayType() && t2.isArrayType()) {
-                // Subtype of Array do not support cast now, for example:
-                //     Array<Int8> can not cast to Array<Int32>
                 return t1.matchesType(t2);
             } else if (t1.isMapType() && t2.isMapType()) {
                 return true;
diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py
index af88200166..fc57c9bda2 100755
--- a/gensrc/script/doris_builtins_functions.py
+++ b/gensrc/script/doris_builtins_functions.py
@@ -161,6 +161,32 @@ visible_functions = [
 
     [['cardinality', 'size'], 'BIGINT', ['ARRAY'], '', '', '', 'vec', ''],
 
+    [['array_min'],     'TINYINT',  ['ARRAY_TINYINT'],  '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_min'],     'SMALLINT', ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_min'],     'INT',      ['ARRAY_INT'],      '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_min'],     'BIGINT',   ['ARRAY_BIGINT'],   '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_min'],     'LARGEINT', ['ARRAY_LARGEINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_max'],     'TINYINT',  ['ARRAY_TINYINT'],  '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_max'],     'SMALLINT', ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_max'],     'INT',      ['ARRAY_INT'],      '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_max'],     'BIGINT',   ['ARRAY_BIGINT'],   '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_max'],     'LARGEINT', ['ARRAY_LARGEINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_sum'],     'BIGINT',   ['ARRAY_TINYINT'],  '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_sum'],     'BIGINT',   ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_sum'],     'BIGINT',   ['ARRAY_INT'],      '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_sum'],     'BIGINT',   ['ARRAY_BIGINT'],   '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_sum'],     'LARGEINT', ['ARRAY_LARGEINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_avg'],     'DOUBLE',   ['ARRAY_TINYINT'],  '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_avg'],     'DOUBLE',   ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_avg'],     'DOUBLE',   ['ARRAY_INT'],      '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_avg'],     'DOUBLE',   ['ARRAY_BIGINT'],   '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_avg'],     'DOUBLE',   ['ARRAY_LARGEINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_product'], 'DOUBLE',   ['ARRAY_TINYINT'],  '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_product'], 'DOUBLE',   ['ARRAY_SMALLINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_product'], 'DOUBLE',   ['ARRAY_INT'],      '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_product'], 'DOUBLE',   ['ARRAY_BIGINT'],   '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+    [['array_product'], 'DOUBLE',   ['ARRAY_LARGEINT'], '', '', '', 'vec', 'ALWAYS_NULLABLE'],
+
     # Timestamp functions
     [['unix_timestamp'], 'INT', [],
         '_ZN5doris18TimestampFunctions7to_unixEPN9doris_udf15FunctionContextE',
@@ -899,8 +925,8 @@ visible_functions = [
             '_ZN5doris15StringFunctions4rpadEPN9doris_udf'
             '15FunctionContextERKNS1_9StringValERKNS1_6IntValES6_', '', '', 'vec', ''],
     [['append_trailing_char_if_absent'], 'VARCHAR', ['VARCHAR', 'VARCHAR'],
-	        '_ZN5doris15StringFunctions30append_trailing_char_if_absentEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
-	        '', '', 'vec', 'ALWAYS_NULLABLE'],
+            '_ZN5doris15StringFunctions30append_trailing_char_if_absentEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
+            '', '', 'vec', 'ALWAYS_NULLABLE'],
     [['length'], 'INT', ['VARCHAR'],
             '_ZN5doris15StringFunctions6lengthEPN9doris_udf15FunctionContextERKNS1_9StringValE',
             '', '', 'vec', ''],
@@ -1021,8 +1047,8 @@ visible_functions = [
             '_ZN5doris15StringFunctions4rpadEPN9doris_udf'
             '15FunctionContextERKNS1_9StringValERKNS1_6IntValES6_', '', '', 'vec', ''],
     [['append_trailing_char_if_absent'], 'STRING', ['STRING', 'STRING'],
-	        '_ZN5doris15StringFunctions30append_trailing_char_if_absentEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
-	        '', '', 'vec', 'ALWAYS_NULLABLE'],
+            '_ZN5doris15StringFunctions30append_trailing_char_if_absentEPN9doris_udf15FunctionContextERKNS1_9StringValES6_',
+            '', '', 'vec', 'ALWAYS_NULLABLE'],
     [['length'], 'INT', ['STRING'],
             '_ZN5doris15StringFunctions6lengthEPN9doris_udf15FunctionContextERKNS1_9StringValE',
             '', '', 'vec', ''],
@@ -1275,11 +1301,11 @@ visible_functions = [
     [['to_quantile_state'], 'QUANTILE_STATE', ['VARCHAR', 'FLOAT'],
         '_ZN5doris22QuantileStateFunctions17to_quantile_stateEPN9doris_udf15FunctionContextERKNS1_9StringValE',
         '_ZN5doris22QuantileStateFunctions25to_quantile_state_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE', '', 'vec', ''],
-    
+
     [['quantile_percent'], 'DOUBLE', ['QUANTILE_STATE', 'FLOAT'],
         '_ZN5doris22QuantileStateFunctions16quantile_percentEPN9doris_udf15FunctionContextERNS1_9StringValE',
         '_ZN5doris22QuantileStateFunctions24quantile_percent_prepareEPN9doris_udf15FunctionContextENS2_18FunctionStateScopeE', '', 'vec', ''],
-    
+
 
     # hash functions
     [['murmur_hash3_32'], 'INT', ['VARCHAR', '...'],


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org