You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2022/07/02 15:33:15 UTC

[doris] branch dev-1.0.1 updated: [hotfix][feature](dev-1.0.1) support `max_by` and `min_by` on row-based engine (#10555)

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

morningman pushed a commit to branch dev-1.0.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/dev-1.0.1 by this push:
     new c89166ffd4 [hotfix][feature](dev-1.0.1) support `max_by` and `min_by` on row-based engine (#10555)
c89166ffd4 is described below

commit c89166ffd4ee2fa5b6cbbea0ed909741eb2a39af
Author: Gabriel <ga...@gmail.com>
AuthorDate: Sat Jul 2 23:33:11 2022 +0800

    [hotfix][feature](dev-1.0.1) support `max_by` and `min_by` on row-based engine (#10555)
    
    This is because in previous, we only implement `max/min_by` function in vec engine.
    But the vec is not working well will outer join operation for now, so use can not use
    `max/min_by` with outer join in vec engine.
    
    So I implement the `max/min_by` in non-vec engine so that user can use it in non-vec.
    This is just a compromise way and I just push it to dev-1.0.1 branch.
    
    We are still working on supporting outer join in vec engine in master branch.
    So maybe I will not push this implement to master branch.
---
 be/src/exprs/aggregate_functions.cpp               | 441 ++++++++++++++++++++-
 be/src/exprs/aggregate_functions.h                 |  14 +
 .../org/apache/doris/analysis/AggregateInfo.java   |   5 +-
 .../java/org/apache/doris/catalog/FunctionSet.java | 167 +++++++-
 4 files changed, 608 insertions(+), 19 deletions(-)

diff --git a/be/src/exprs/aggregate_functions.cpp b/be/src/exprs/aggregate_functions.cpp
index 3e2f4b3fe5..885c52d5fe 100644
--- a/be/src/exprs/aggregate_functions.cpp
+++ b/be/src/exprs/aggregate_functions.cpp
@@ -363,6 +363,295 @@ struct DecimalV2AvgState {
     int64_t count = 0;
 };
 
+template <typename T, typename KT>
+struct MaxMinByState {
+    T val1;
+    KT val2;
+    bool flag = false;
+};
+
+template <typename T, typename KT>
+struct MaxMinByStateWithString {
+    T val1;
+    KT val2;
+    bool flag = false;
+
+    static const int STRING_LENGTH_RECORD_LENGTH = 4;
+    StringVal serialize(FunctionContext* ctx) {
+        // calculate total serialize buffer length
+        int total_serialized_set_length = 1;
+        if constexpr (std::is_same_v<StringVal, T>) {
+            total_serialized_set_length += STRING_LENGTH_RECORD_LENGTH + ((StringVal)val1).len;
+        } else {
+            total_serialized_set_length += STRING_LENGTH_RECORD_LENGTH + sizeof(T);
+        }
+
+        if constexpr (std::is_same_v<StringVal, KT>) {
+            total_serialized_set_length += STRING_LENGTH_RECORD_LENGTH + ((StringVal)val2).len;
+        } else {
+            total_serialized_set_length += STRING_LENGTH_RECORD_LENGTH + sizeof(KT);
+        }
+
+        StringVal result(ctx, total_serialized_set_length);
+        uint8_t* writer = result.ptr;
+        // type
+        *writer = flag;
+        writer++;
+
+        if constexpr (std::is_same_v<StringVal, T>) {
+            *(int*)writer = ((StringVal)val1).len;
+            writer += STRING_LENGTH_RECORD_LENGTH;
+            memcpy(writer, ((StringVal)val1).ptr, ((StringVal)val1).len);
+            writer += ((StringVal)val1).len;
+        } else {
+            *(int*)writer = sizeof(T);
+            writer += STRING_LENGTH_RECORD_LENGTH;
+            *(T*)writer = val1;
+            writer += sizeof(T);
+        }
+
+        if constexpr (std::is_same_v<StringVal, KT>) {
+            *(int*)writer = ((StringVal)val2).len;
+            writer += STRING_LENGTH_RECORD_LENGTH;
+            memcpy(writer, ((StringVal)val2).ptr, ((StringVal)val2).len);
+        } else {
+            *(int*)writer = sizeof(KT);
+            writer += STRING_LENGTH_RECORD_LENGTH;
+            *(KT*)writer = val2;
+        }
+        return result;
+    }
+
+    void deserialize(const StringVal& src) {
+        uint8_t* reader = src.ptr;
+        // skip type ,no used now
+        flag = (bool)*reader;
+        reader++;
+        const uint8_t* end = src.ptr + src.len;
+
+        const int val1_length = *(int*)reader;
+        reader += STRING_LENGTH_RECORD_LENGTH;
+
+        if constexpr (std::is_same_v<StringVal, T>) {
+            StringVal value((uint8_t*)reader, val1_length);
+            val1 = value;
+        } else {
+            val1 = *(T*)reader;
+        }
+        reader += val1_length;
+
+        const int val2_length = *(int*)reader;
+        reader += STRING_LENGTH_RECORD_LENGTH;
+        if constexpr (std::is_same_v<StringVal, KT>) {
+            StringVal value((uint8_t*)reader, val2_length);
+            val2 = value;
+        } else {
+            val2 = *(KT*)reader;
+        }
+        reader += val2_length;
+        DCHECK(reader == end);
+    }
+};
+
+template <typename T, typename KT>
+void AggregateFunctions::maxminby_init(FunctionContext* ctx, StringVal* dst) {
+    dst->is_null = false;
+    int len;
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        len = sizeof(MaxMinByStateWithString<T, KT>);
+        dst->ptr = (uint8_t*)new MaxMinByStateWithString<T, KT>;
+    } else {
+        len = sizeof(MaxMinByState<T, KT>);
+        dst->ptr = (uint8_t*)new MaxMinByState<T, KT>;
+    }
+    dst->len = len;
+}
+
+template <typename T, bool max_by_fn>
+constexpr bool maxminby_compare(T x, T y) {
+    if constexpr (max_by_fn) {
+        if constexpr (std::is_same_v<T, StringVal>) {
+            return x.to_string() > y.to_string();
+        } else if constexpr (std::is_same_v<T, DateTimeVal>) {
+            return x.packed_time > y.packed_time;
+        } else {
+            return x.val > y.val;
+        }
+    } else {
+        if constexpr (std::is_same_v<T, StringVal>) {
+            return x.to_string() < y.to_string();
+        } else if constexpr (std::is_same_v<T, DateTimeVal>) {
+            return x.packed_time < y.packed_time;
+        } else {
+            return x.val < y.val;
+        }
+    }
+}
+
+template <typename T, typename KT, bool max_by_fn>
+void AggregateFunctions::maxminby_update(FunctionContext* ctx, const T& slot1, const KT& slot2,
+                                         StringVal* dst) {
+    if (slot1.is_null) {
+        return;
+    }
+    DCHECK(dst->ptr != nullptr);
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        DCHECK_EQ(sizeof(MaxMinByStateWithString<T, KT>), dst->len);
+        auto max_by = reinterpret_cast<MaxMinByStateWithString<T, KT>*>(dst->ptr);
+
+        bool condition = !max_by->flag || maxminby_compare<KT, max_by_fn>(slot2, max_by->val2);
+        if (condition) {
+            if constexpr (std::is_same_v<T, StringVal>) {
+                max_by->val1 = StringVal::copy_from(ctx, slot1.ptr, slot1.len);
+            } else {
+                max_by->val1 = slot1;
+            }
+            if constexpr (std::is_same_v<KT, StringVal>) {
+                max_by->val2 = StringVal::copy_from(ctx, slot2.ptr, slot2.len);
+            } else {
+                max_by->val2 = slot2;
+            }
+            if (!max_by->flag) {
+                max_by->flag = true;
+            }
+        }
+    } else {
+        DCHECK_EQ(sizeof(MaxMinByState<T, KT>), dst->len);
+        auto max_by = reinterpret_cast<MaxMinByState<T, KT>*>(dst->ptr);
+
+        bool condition = !max_by->flag || maxminby_compare<KT, max_by_fn>(slot2, max_by->val2);
+        ;
+        if (condition) {
+            max_by->val1 = slot1;
+            max_by->val2 = slot2;
+            if (!max_by->flag) {
+                max_by->flag = true;
+            }
+        }
+    }
+}
+
+template <typename T, typename KT>
+StringVal AggregateFunctions::maxminby_serialize(FunctionContext* ctx, const StringVal& src) {
+    DCHECK(!src.is_null);
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        auto state = reinterpret_cast<MaxMinByStateWithString<T, KT>*>(src.ptr);
+        StringVal result = state->serialize(ctx);
+        delete (MaxMinByStateWithString<T, KT>*)src.ptr;
+        return result;
+    } else {
+        StringVal result(ctx, src.len);
+        memcpy(result.ptr, src.ptr, src.len);
+        delete (MaxMinByState<T, KT>*)src.ptr;
+        return result;
+    }
+}
+
+template <typename T, typename KT, bool max_by_fn>
+void AggregateFunctions::maxminby_merge(FunctionContext* ctx, const StringVal& src,
+                                        StringVal* dst) {
+    if (src.is_null || src.ptr == nullptr) {
+        return;
+    }
+    DCHECK(dst->ptr != nullptr);
+
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        DCHECK_EQ(sizeof(MaxMinByStateWithString<T, KT>), dst->len);
+
+        // deserialize src
+        StringVal src_state_val;
+        int len = sizeof(MaxMinByStateWithString<T, KT>);
+        src_state_val.is_null = false;
+        src_state_val.len = len;
+        src_state_val.ptr = (uint8_t*)new MaxMinByStateWithString<T, KT>;
+        auto src_state = reinterpret_cast<MaxMinByStateWithString<T, KT>*>(src_state_val.ptr);
+        src_state->deserialize(src);
+
+        auto max_by2 = reinterpret_cast<MaxMinByStateWithString<T, KT>*>(dst->ptr);
+        if (!src_state->flag) {
+            return;
+        }
+        bool condition = max_by2->flag == 0 ||
+                         maxminby_compare<KT, max_by_fn>(src_state->val2, max_by2->val2);
+        if (condition) {
+            if constexpr (std::is_same_v<T, StringVal>) {
+                max_by2->val1 = StringVal::copy_from(ctx, src_state->val1.ptr, src_state->val1.len);
+            } else {
+                max_by2->val1 = src_state->val1;
+            }
+            if constexpr (std::is_same_v<KT, StringVal>) {
+                max_by2->val2 = StringVal::copy_from(ctx, src_state->val2.ptr, src_state->val2.len);
+            } else {
+                max_by2->val2 = src_state->val2;
+            }
+            if (!max_by2->flag) {
+                max_by2->flag = true;
+            }
+        }
+    } else {
+        DCHECK_EQ(sizeof(MaxMinByState<T, KT>), dst->len);
+        auto max_by1 = reinterpret_cast<MaxMinByState<T, KT>*>(src.ptr);
+        auto max_by2 = reinterpret_cast<MaxMinByState<T, KT>*>(dst->ptr);
+        if (!max_by1->flag) {
+            return;
+        }
+        bool condition =
+                max_by2->flag == 0 || maxminby_compare<KT, max_by_fn>(max_by1->val2, max_by2->val2);
+        ;
+        if (condition) {
+            max_by2->val2 = max_by1->val2;
+            max_by2->val1 = max_by1->val1;
+            if (!max_by2->flag) {
+                max_by2->flag = true;
+            }
+        }
+    }
+}
+
+template <typename T, typename KT>
+T AggregateFunctions::maxminby_get_value(FunctionContext* ctx, const StringVal& src) {
+    if (src.ptr == nullptr) {
+        return T::null();
+    }
+
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        auto state = reinterpret_cast<MaxMinByStateWithString<T, KT>*>(src.ptr);
+        if (!state->flag) {
+            return T::null();
+        }
+        if constexpr (std::is_same_v<T, StringVal>) {
+            return StringVal::copy_from(ctx, state->val1.ptr, state->val1.len);
+        } else {
+            return state->val1;
+        }
+    } else {
+        auto state = reinterpret_cast<MaxMinByState<T, KT>*>(src.ptr);
+        if (!state->flag) {
+            return T::null();
+        }
+        return state->val1;
+    }
+}
+
+template <typename T, typename KT>
+T AggregateFunctions::maxminby_finalize(doris_udf::FunctionContext* ctx,
+                                        const doris_udf::StringVal& src) {
+    if (src.ptr == nullptr) {
+        return T::null();
+    }
+    if (src.is_null) {
+        return T::null();
+    }
+    T result = maxminby_get_value<T, KT>(ctx, src);
+
+    if constexpr (std::is_same_v<T, StringVal> || std::is_same_v<KT, StringVal>) {
+        delete (MaxMinByStateWithString<T, KT>*)src.ptr;
+    } else {
+        delete (MaxMinByState<T, KT>*)src.ptr;
+    }
+    return result;
+}
+
 void AggregateFunctions::avg_init(FunctionContext* ctx, StringVal* dst) {
     dst->is_null = false;
     dst->len = sizeof(AvgState);
@@ -1077,7 +1366,7 @@ void AggregateFunctions::hll_merge(FunctionContext* ctx, const StringVal& src, S
     DCHECK(!src.is_null);
     DCHECK_EQ(dst->len, std::pow(2, HLL_COLUMN_PRECISION));
     DCHECK_EQ(src.len, std::pow(2, HLL_COLUMN_PRECISION));
-    
+
     for (int i = 0; i < src.len; ++i) {
         dst->ptr[i] = (dst->ptr[i] < src.ptr[i] ? src.ptr[i] : dst->ptr[i]);
     }
@@ -2670,6 +2959,156 @@ template void AggregateFunctions::avg_remove<doris_udf::SmallIntVal>(doris_udf::
                                                                      doris_udf::SmallIntVal const&,
                                                                      doris_udf::StringVal*);
 
+#define MAXMINBY_FUNCTION(TYPE_T, TYPE_KT)                                                         \
+    template void AggregateFunctions::maxminby_merge<TYPE_T, TYPE_KT, true>(                       \
+            FunctionContext * ctx, const StringVal& src, StringVal* dst);                          \
+    template void AggregateFunctions::maxminby_merge<TYPE_T, TYPE_KT, false>(                      \
+            FunctionContext * ctx, const StringVal& src, StringVal* dst);                          \
+    template StringVal AggregateFunctions::maxminby_serialize<TYPE_T, TYPE_KT>(                    \
+            FunctionContext * ctx, const StringVal& src);                                          \
+    template TYPE_T AggregateFunctions::maxminby_get_value<TYPE_T, TYPE_KT>(FunctionContext * ctx, \
+                                                                            const StringVal& src); \
+    template TYPE_T AggregateFunctions::maxminby_finalize<TYPE_T, TYPE_KT>(FunctionContext * ctx,  \
+                                                                           const StringVal& src);  \
+    template void AggregateFunctions::maxminby_init<TYPE_T, TYPE_KT>(                              \
+            doris_udf::FunctionContext * ctx, doris_udf::StringVal * dst);                         \
+    template void AggregateFunctions::maxminby_update<TYPE_T, TYPE_KT, false>(                     \
+            doris_udf::FunctionContext*, TYPE_T const&, TYPE_KT const&, doris_udf::StringVal*);    \
+    template void AggregateFunctions::maxminby_update<TYPE_T, TYPE_KT, true>(                      \
+            doris_udf::FunctionContext*, TYPE_T const&, TYPE_KT const&, doris_udf::StringVal*);
+
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::TinyIntVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::SmallIntVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::IntVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::BigIntVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::LargeIntVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::FloatVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::DoubleVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::DecimalV2Val, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::BooleanVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::DateTimeVal, doris_udf::StringVal)
+
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::TinyIntVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::IntVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::SmallIntVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::BigIntVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::LargeIntVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::FloatVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::DoubleVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::DecimalV2Val)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::BooleanVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::DateTimeVal)
+MAXMINBY_FUNCTION(doris_udf::StringVal, doris_udf::StringVal)
+
 template void AggregateFunctions::max_init<BooleanVal>(doris_udf::FunctionContext*,
                                                        BooleanVal* dst);
 template void AggregateFunctions::max_init<TinyIntVal>(doris_udf::FunctionContext*,
diff --git a/be/src/exprs/aggregate_functions.h b/be/src/exprs/aggregate_functions.h
index de96cccf10..b0cda34e60 100644
--- a/be/src/exprs/aggregate_functions.h
+++ b/be/src/exprs/aggregate_functions.h
@@ -104,6 +104,20 @@ public:
 
     static StringVal percentile_approx_serialize(FunctionContext* ctx, const StringVal& state_sv);
 
+    template <typename T, typename KT>
+    static void maxminby_init(doris_udf::FunctionContext* ctx, doris_udf::StringVal* dst);
+    template <typename T, typename KT, bool max_by_fn>
+    static void maxminby_update(doris_udf::FunctionContext* ctx, const T& slot1, const KT& slot2,
+                                doris_udf::StringVal* dst);
+    template <typename T, typename KT>
+    static StringVal maxminby_serialize(FunctionContext* ctx, const StringVal& src);
+    template <typename T, typename KT, bool max_by_fn>
+    static void maxminby_merge(FunctionContext* ctx, const StringVal& src, StringVal* dst);
+    template <typename T, typename KT>
+    static T maxminby_get_value(doris_udf::FunctionContext* ctx, const doris_udf::StringVal& val);
+    template <typename T, typename KT>
+    static T maxminby_finalize(doris_udf::FunctionContext* ctx, const doris_udf::StringVal& val);
+
     // Implementation of Avg.
     // TODO: Change this to use a fixed-sized BufferVal as intermediate type.
     static void avg_init(doris_udf::FunctionContext* ctx, doris_udf::StringVal* dst);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AggregateInfo.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AggregateInfo.java
index f02d15c7b9..74facd0a55 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AggregateInfo.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AggregateInfo.java
@@ -19,6 +19,7 @@ package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.FunctionSet;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.util.VectorizedUtil;
 import org.apache.doris.planner.DataPartition;
 import org.apache.doris.thrift.TPartitionType;
 
@@ -455,8 +456,8 @@ public final class AggregateInfo extends AggregateInfoBase {
             List<Expr> paramExprs = new ArrayList<>();
             // TODO(zhannngchen), change intermediate argument to a list, and remove this
             // ad-hoc logic
-            if (inputExpr.fn.functionName().equals("max_by") ||
-                    inputExpr.fn.functionName().equals("min_by")) {
+            if ((inputExpr.fn.functionName().equals("max_by") ||
+                    inputExpr.fn.functionName().equals("min_by")) && VectorizedUtil.isVectorized()) {
                 paramExprs.addAll(inputExpr.getFnParams().exprs());
             } else {
                 paramExprs.add(new SlotRef(inputDesc.getSlots().get(i + getGroupingExprs().size())));
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java
index 8096d14631..d0ff5711f3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java
@@ -402,8 +402,8 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 .put(Type.DECIMALV2,
                         "16knuth_var_updateEPN9doris_udf15FunctionContextERKNS1_12DecimalV2ValEPNS1_9StringValE")
                 .build();
-                
-                                                               
+
+
     private static final Map<Type, String> STDDEV_REMOVE_SYMBOL =
         ImmutableMap.<Type, String>builder()
                 .put(Type.TINYINT,
@@ -420,7 +420,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         "16knuth_var_removeIN9doris_udf9DoubleValEEEvPNS2_15FunctionContextERKT_PNS2_9StringValE")
                 .put(Type.DECIMALV2,
                         "16knuth_var_removeEPN9doris_udf15FunctionContextERKNS1_12DecimalV2ValEPNS1_9StringValE")
-                .build();                
+                .build();
     private static final Map<Type, String> STDDEV_MERGE_SYMBOL =
         ImmutableMap.<Type, String>builder()
                 .put(Type.TINYINT,
@@ -509,8 +509,8 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 "26knuth_stddev_pop_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
                 .put(Type.DECIMALV2,
                 "36decimalv2_knuth_stddev_pop_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
-                .build(); 
-                  
+                .build();
+
     private static final Map<Type, String> VAR_FINALIZE_SYMBOL =
         ImmutableMap.<Type, String>builder()
                 .put(Type.TINYINT,
@@ -545,8 +545,8 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         "19knuth_var_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
                 .put(Type.DECIMALV2,
                         "29decimalv2_knuth_var_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
-                .build(); 
-               
+                .build();
+
     private static final Map<Type, String> VAR_POP_FINALIZE_SYMBOL =
         ImmutableMap.<Type, String>builder()
                 .put(Type.TINYINT,
@@ -581,7 +581,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         "23knuth_var_pop_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
                 .put(Type.DECIMALV2,
                         "33decimalv2_knuth_var_pop_get_valueEPN9doris_udf15FunctionContextERKNS1_9StringValE")
-                .build();                
+                .build();
     public static final String HLL_HASH = "hll_hash";
     public static final String HLL_UNION = "hll_union";
 
@@ -1334,6 +1334,141 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 prefix + "17count_star_removeEPN9doris_udf15FunctionContextEPNS1_9BigIntValE",
                 null, false, true, true, true));
 
+        Map<ScalarType, String> symbolsMap = new HashMap<>();
+        symbolsMap.put(Type.INT, "6IntVal");
+        symbolsMap.put(Type.BOOLEAN, "10BooleanVal");
+        symbolsMap.put(Type.FLOAT, "8FloatVal");
+        symbolsMap.put(Type.TINYINT, "10TinyIntVal");
+        symbolsMap.put(Type.SMALLINT, "11SmallIntVal");
+        symbolsMap.put(Type.LARGEINT, "11LargeIntVal");
+        symbolsMap.put(Type.BIGINT, "9BigIntVal");
+        symbolsMap.put(Type.DOUBLE, "9DoubleVal");
+        symbolsMap.put(Type.DECIMALV2, "12DecimalV2Val");
+        symbolsMap.put(Type.DATE, "11DateTimeVal");
+        symbolsMap.put(Type.DATETIME, "11DateTimeVal");
+        symbolsMap.put(Type.STRING, "9StringVal");
+        symbolsMap.put(Type.VARCHAR, "9StringVal");
+        symbolsMap.put(Type.CHAR, "9StringVal");
+        for (ScalarType type1: symbolsMap.keySet()) {
+            for (ScalarType type2: symbolsMap.keySet()) {
+                if (symbolsMap.get(type1).equals(symbolsMap.get(type2)) && !type1.isStringType()) {
+                    addBuiltin(AggregateFunction.createBuiltin("max_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ES3_EEvPNS2_15FunctionContextEPNS2_9StringValE",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb1EEEvPNS2_15FunctionContextERKT_RKT0_PNS2_9StringValE",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb1EEEvPNS2_15FunctionContextERKNS2_9StringValEPS6_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EENS2_9StringValEPNS2_15FunctionContextERKS4_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            false, true, false));
+                } else if (type1.isStringType() && !symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("max_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPS3_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKT_RKT0_PS3_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKS3_PS3_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEES3_PNS2_15FunctionContextERKS3_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS3_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS3_",
+                            false, true, false));
+                } else if (type2.isStringType() && !symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("max_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPS4_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKT_RKT0_PS4_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKS4_PS4_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEES4_PNS2_15FunctionContextERKS4_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS4_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS4_",
+                            false, true, false));
+                } else if (type1.isStringType() && symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("max_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ES3_EEvPNS2_15FunctionContextEPS3_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb1EEEvPNS2_15FunctionContextERKT_RKT0_PS3_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb1EEEvPNS2_15FunctionContextERKS3_PS3_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EES3_PNS2_15FunctionContextERKS3_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKS3_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKS3_",
+                            false, true, false));
+                } else {
+                    addBuiltin(AggregateFunction.createBuiltin("max_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPNS2_9StringValE",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKT_RKT0_PNS2_9StringValE",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb1EEEvPNS2_15FunctionContextERKNS2_9StringValEPS7_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEENS2_9StringValEPNS2_15FunctionContextERKS5_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            false, true, false));
+                }
+            }
+        }
+        for (ScalarType type1: symbolsMap.keySet()) {
+            for (ScalarType type2: symbolsMap.keySet()) {
+                if (symbolsMap.get(type1).equals(symbolsMap.get(type2)) && !type1.isStringType()) {
+                    addBuiltin(AggregateFunction.createBuiltin("min_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ES3_EEvPNS2_15FunctionContextEPNS2_9StringValE",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb0EEEvPNS2_15FunctionContextERKT_RKT0_PNS2_9StringValE",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb0EEEvPNS2_15FunctionContextERKNS2_9StringValEPS6_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EENS2_9StringValEPNS2_15FunctionContextERKS4_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            false, true, false));
+                } else if (type1.isStringType() && !symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("min_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPS3_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKT_RKT0_PS3_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKS3_PS3_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEES3_PNS2_15FunctionContextERKS3_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS3_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS3_",
+                            false, true, false));
+                } else if (type2.isStringType() && !symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("min_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPS4_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKT_RKT0_PS4_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKS4_PS4_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEES4_PNS2_15FunctionContextERKS4_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS4_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKS4_",
+                            false, true, false));
+                } else if (type1.isStringType() && symbolsMap.get(type1).equals(symbolsMap.get(type2))) {
+                    addBuiltin(AggregateFunction.createBuiltin("min_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ES3_EEvPNS2_15FunctionContextEPS3_",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb0EEEvPNS2_15FunctionContextERKT_RKT0_PS3_",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ES3_Lb0EEEvPNS2_15FunctionContextERKS3_PS3_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EES3_PNS2_15FunctionContextERKS3_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKS3_",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ES3_EET_PNS2_15FunctionContextERKS3_",
+                            false, true, false));
+                } else {
+                    addBuiltin(AggregateFunction.createBuiltin("min_by",
+                            Lists.<Type>newArrayList(type1, type2), type1, Type.VARCHAR,
+                            prefix + "13maxminby_initIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEEvPNS2_15FunctionContextEPNS2_9StringValE",
+                            prefix + "15maxminby_updateIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKT_RKT0_PNS2_9StringValE",
+                            prefix + "14maxminby_mergeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "ELb0EEEvPNS2_15FunctionContextERKNS2_9StringValEPS7_",
+                            prefix + "18maxminby_serializeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEENS2_9StringValEPNS2_15FunctionContextERKS5_",
+                            prefix + "18maxminby_get_valueIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            null,
+                            prefix + "17maxminby_finalizeIN9doris_udf" + symbolsMap.get(type1) + "ENS2_" + symbolsMap.get(type2) + "EEET_PNS2_15FunctionContextERKNS2_9StringValE",
+                            false, true, false));
+                }
+            }
+        }
         // windowFunnel
         addBuiltin(AggregateFunction.createBuiltin(FunctionSet.WINDOW_FUNNEL,
                 Lists.newArrayList(Type.BIGINT, Type.STRING, Type.DATETIME, Type.BOOLEAN),
@@ -1465,7 +1600,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                     prefix + MULTI_DISTINCT_COUNT_FINALIZE_SYMBOL.get(t),
                     false, true, true, true));
 
-                
+
             } else if (t.equals(Type.DATE) || t.equals(Type.DATETIME)) {
                addBuiltin(AggregateFunction.createBuiltin("multi_distinct_count", Lists.newArrayList(t),
                     Type.BIGINT,
@@ -1785,7 +1920,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         null, prefix + STDDEV_POP_GET_VALUE_SYMBOL.get(t), prefix + STDDEV_REMOVE_SYMBOL.get(t),
                         prefix + STDDEV_POP_FINALIZE_SYMBOL.get(t),
                         false, true, false));
-                        
+
                 addBuiltin(AggregateFunction.createBuiltin("stddev_samp",
                         Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), Type.VARCHAR,
                         prefix + STDDEV_INIT_SYMBOL.get(t),
@@ -1829,7 +1964,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         null, null, null,
                         prefix + STDDEV_POP_FINALIZE_SYMBOL.get(t),
                         false, true, false, true));
-                
+
                 //vec: variance variance_samp var_samp variance_pop var_pop
                 addBuiltin(AggregateFunction.createBuiltin("variance",
                         Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), t,
@@ -1870,7 +2005,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                         prefix + STDDEV_MERGE_SYMBOL.get(t),
                         null, null, null,
                         prefix + VAR_FINALIZE_SYMBOL.get(t),
-                        false, true, false, true));                        
+                        false, true, false, true));
 
                 addBuiltin(AggregateFunction.createBuiltin("variance",
                         Lists.newArrayList(t), STDDEV_RETTYPE_SYMBOL.get(t), Type.VARCHAR,
@@ -2109,7 +2244,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 "",
                 "",
                 true, false, true, true));
-      
+
               //Percentile
         addBuiltin(AggregateFunction.createBuiltin("percentile",
                 Lists.newArrayList(Type.BIGINT, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR,
@@ -2164,7 +2299,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 prefix + "23percentile_approx_mergeEPN9doris_udf15FunctionContextERKNS1_9StringValEPS4_",
                 prefix + "27percentile_approx_serializeEPN9doris_udf15FunctionContextERKNS1_9StringValE",
                 prefix + "26percentile_approx_finalizeEPN9doris_udf15FunctionContextERKNS1_9StringValE",
-                false, true, false, true)); 
+                false, true, false, true));
 
         // Avg
         // TODO: switch to CHAR(sizeof(AvgIntermediateType) when that becomes available
@@ -2320,7 +2455,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                 prefix + "17count_star_updateEPN9doris_udf15FunctionContextEPNS1_9BigIntValE",
                 prefix + "11count_mergeEPN9doris_udf15FunctionContextERKNS1_9BigIntValEPS4_",
                 null, null));
-        
+
         //vec Rank
         addBuiltin(AggregateFunction.createAnalyticBuiltin("rank",
                 Lists.<Type>newArrayList(), Type.BIGINT, Type.VARCHAR,
@@ -2399,7 +2534,7 @@ public class FunctionSet<min_initIN9doris_udf12DecimalV2ValEEEvPNS2_15FunctionCo
                     prefix + OFFSET_FN_INIT_SYMBOL.get(t),
                     prefix + OFFSET_FN_UPDATE_SYMBOL.get(t),
                     null, t.isStringType() ? stringValGetValue : null, null));
-                    
+
             addBuiltin(AggregateFunction.createAnalyticBuiltin(
                     "lead", Lists.newArrayList(t, Type.BIGINT, t), t, t,
                     prefix + OFFSET_FN_INIT_SYMBOL.get(t),


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