Code review comment: I this function internal can be represented as four-argument function: topN(columnRecall, sortKeyColumn, N, desc|asc) then use this function to implement max_by and min_by.

Code under review:
private static void analyzeBuiltinAggFunction(FunctionCallExpr functionCallExpr) {
        FunctionName fnName = functionCallExpr.getFnName();
        FunctionParams fnParams = functionCallExpr.getParams();

        if (fnParams.isStar() && !fnName.getFunction().equals(FunctionSet.COUNT)) {
            throw new SemanticException("'*' can only be used in conjunction with COUNT: " + functionCallExpr.toSql());
        }

        if (fnName.getFunction().equals(FunctionSet.COUNT)) {
            
            if (functionCallExpr.getChildren().size() > 1 && !fnParams.isDistinct()) {
                throw new SemanticException(
                        "COUNT must have DISTINCT for multiple arguments: " + functionCallExpr.toSql());
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.GROUP_CONCAT)) {
            if (functionCallExpr.getChildren().size() > 2 || functionCallExpr.getChildren().isEmpty()) {
                throw new SemanticException(
                        "group_concat requires one or two parameters: " + functionCallExpr.toSql());
            }

            if (fnParams.isDistinct()) {
                throw new SemanticException("group_concat does not support DISTINCT");
            }

            Expr arg0 = functionCallExpr.getChild(0);
            if (!arg0.getType().isStringType() && !arg0.getType().isNull()) {
                throw new SemanticException(
                        "group_concat requires first parameter to be of getType() STRING: " + functionCallExpr.toSql());
            }

            if (functionCallExpr.getChildren().size() == 2) {
                Expr arg1 = functionCallExpr.getChild(1);
                if (!arg1.getType().isStringType() && !arg1.getType().isNull()) {
                    throw new SemanticException(
                            "group_concat requires second parameter to be of getType() STRING: " +
                                    functionCallExpr.toSql());
                }
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.LAG)
                || fnName.getFunction().equals(FunctionSet.LEAD)) {
            if (!functionCallExpr.isAnalyticFnCall()) {
                throw new SemanticException(fnName.getFunction() + " only used in analytic function");
            } else {
                if (functionCallExpr.getChildren().size() > 2) {
                    if (!functionCallExpr.getChild(2).isConstant()) {
                        throw new SemanticException(
                                "The default parameter (parameter 3) of LAG must be a constant: "
                                        + functionCallExpr.toSql());
                    }
                }
                return;
            }
        }

        if (FunctionSet.onlyAnalyticUsedFunctions.contains(fnName.getFunction())) {
            if (!functionCallExpr.isAnalyticFnCall()) {
                throw new SemanticException(fnName.getFunction() + " only used in analytic function");
            }
        }

        
        Expr arg = functionCallExpr.getChild(0);
        if (arg == null) {
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAY_AGG)) {
            if (fnParams.isDistinct()) {
                throw new SemanticException("array_agg does not support DISTINCT");
            }
            if (arg.getType().isDecimalV3()) {
                throw new SemanticException("array_agg does not support DecimalV3");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAYS_OVERLAP)) {
            if (functionCallExpr.getChildren().size() != 2) {
                throw new SemanticException("arrays_overlap only support 2 parameters");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAY_FILTER)) {
            if (functionCallExpr.getChildren().size() != 2) {
                throw new SemanticException("array_filter only support 2 parameters");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.RETENTION)) {
            if (!arg.getType().isArrayType()) {
                throw new SemanticException("retention only support Array<BOOLEAN>");
            }
            ArrayType type = (ArrayType) arg.getType();
            if (!type.getItemType().isBoolean()) {
                throw new SemanticException("retention only support Array<BOOLEAN>");
            }
            
        }

        if (fnName.getFunction().equals(FunctionSet.WINDOW_FUNNEL)) {
            Expr modeArg = functionCallExpr.getChild(2);
            if (modeArg instanceof IntLiteral) {
                IntLiteral modeIntLiteral = (IntLiteral) modeArg;
                long modeValue = modeIntLiteral.getValue();
                if (modeValue < 0 || modeValue > 3) {
                    throw new SemanticException("mode argument's range must be [0-3]");
                }
            } else {
                throw new SemanticException("mode argument must be numerical type");
            }

            Expr windowArg = functionCallExpr.getChild(0);
            if (windowArg instanceof IntLiteral) {
                IntLiteral windowIntLiteral = (IntLiteral) windowArg;
                long windowValue = windowIntLiteral.getValue();
                if (windowValue < 0) {
                    throw new SemanticException("window argument must >= 0");
                }
            } else {
                throw new SemanticException("window argument must be numerical type");
            }
        }
        
        if (fnName.getFunction().equalsIgnoreCase(FunctionSet.MAX_BY)) {
            if (functionCallExpr.getChildren().size() != 2 || functionCallExpr.getChildren().isEmpty()) {
                throw new SemanticException(
                        "max_by requires two parameters: " + functionCallExpr.toSql());
            }
            
            if (functionCallExpr.getChild(0).isConstant() || functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("max_by function args must be column");
            }
            
            fnParams.setIsDistinct(false);  

            Type maxByType = functionCallExpr.getChild(1).getType();
            if (!maxByType.canApplyToNumeric()) {
                throw new SemanticException(Type.ONLY_METRIC_TYPE_ERROR_MSG);
            }
            
            return;
        }

        
        if ((fnName.getFunction().equals(FunctionSet.SUM)
                || fnName.getFunction().equals(FunctionSet.AVG))
                && ((!arg.getType().isNumericType() && !arg.getType().isBoolean()
                && !arg.getType().isStringType() && !arg.getType().isNull() &&
                !(arg instanceof NullLiteral)) ||
                !arg.getType().canApplyToNumeric())) {
            throw new SemanticException(
                    fnName.getFunction() + " requires a numeric parameter: " + functionCallExpr.toSql());
        }
        if (fnName.getFunction().equals(FunctionSet.SUM_DISTINCT)
                && ((!arg.getType().isNumericType() && !arg.getType().isNull() && !(arg instanceof NullLiteral)) ||
                !arg.getType().canApplyToNumeric())) {
            throw new SemanticException(
                    "SUM_DISTINCT requires a numeric parameter: " + functionCallExpr.toSql());
        }

        if ((fnName.getFunction().equals(FunctionSet.MIN)
                || fnName.getFunction().equals(FunctionSet.MAX)
                || fnName.getFunction().equals(FunctionSet.NDV)
                || fnName.getFunction().equals(FunctionSet.APPROX_COUNT_DISTINCT))
                && !arg.getType().canApplyToNumeric()) {
            throw new SemanticException(Type.ONLY_METRIC_TYPE_ERROR_MSG);
        }

        if ((fnName.getFunction().equals(FunctionSet.BITMAP_UNION_INT) && !arg.getType().isIntegerType())) {
            throw new SemanticException("BITMAP_UNION_INT params only support Integer getType()");
        }

        if (fnName.getFunction().equals(FunctionSet.INTERSECT_COUNT)) {
            if (functionCallExpr.getChildren().size() <= 2) {
                throw new SemanticException("intersect_count(bitmap_column, column_to_filter, filter_values) " +
                        "function requires at least three parameters");
            }

            Type inputType = functionCallExpr.getChild(0).getType();
            if (!inputType.isBitmapType()) {
                throw new SemanticException(
                        "intersect_count function first argument should be of BITMAP getType(), but was " + inputType);
            }

            if (functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("intersect_count function filter_values arg must be column");
            }

            for (int i = 2; i < functionCallExpr.getChildren().size(); i++) {
                if (!functionCallExpr.getChild(i).isConstant()) {
                    throw new SemanticException("intersect_count function filter_values arg must be constant");
                }
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.BITMAP_COUNT)
                || fnName.getFunction().equals(FunctionSet.BITMAP_UNION)
                || fnName.getFunction().equals(FunctionSet.BITMAP_UNION_COUNT)
                || fnName.getFunction().equals(FunctionSet.BITMAP_INTERSECT)) {
            if (functionCallExpr.getChildren().size() != 1) {
                throw new SemanticException(fnName + " function could only have one child");
            }
            Type inputType = functionCallExpr.getChild(0).getType();
            if (!inputType.isBitmapType()) {
                throw new SemanticException(
                        fnName + " function's argument should be of BITMAP getType(), but was " + inputType);
            }
            return;
        }

        if ((fnName.getFunction().equals(FunctionSet.HLL_UNION_AGG)
                || fnName.getFunction().equals(FunctionSet.HLL_UNION)
                || fnName.getFunction().equals(FunctionSet.HLL_CARDINALITY)
                || fnName.getFunction().equals(FunctionSet.HLL_RAW_AGG))
                && !arg.getType().isHllType()) {
            throw new SemanticException(
                    "HLL_UNION_AGG, HLL_RAW_AGG and HLL_CARDINALITY's params must be hll column");
        }

        if (fnName.getFunction().equals(FunctionSet.MIN)
                || fnName.getFunction().equals(FunctionSet.MAX)
                || fnName.getFunction().equals(FunctionSet.NDV)
                || fnName.getFunction().equals(FunctionSet.HLL_UNION_AGG)) {
            fnParams.setIsDistinct(false);  
        }

        if (fnName.getFunction().equals(FunctionSet.PERCENTILE_APPROX)) {
            if (functionCallExpr.getChildren().size() != 2 && functionCallExpr.getChildren().size() != 3) {
                throw new SemanticException("percentile_approx(expr, DOUBLE [, B]) requires two or three parameters");
            }
            if (!functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("percentile_approx requires second parameter must be a constant : "
                        + functionCallExpr.toSql());
            }
            if (functionCallExpr.getChildren().size() == 3) {
                if (!functionCallExpr.getChild(2).isConstant()) {
                    throw new SemanticException("percentile_approx requires the third parameter must be a constant : "
                            + functionCallExpr.toSql());
                }
            }
        }
    }

Line commented on: if (functionCallExpr.getChildren().size() != 2 || functionCallExpr.getChildren().isEmpty()) {

Revised code:
private static void analyzeBuiltinAggFunction(FunctionCallExpr functionCallExpr) {
        FunctionName fnName = functionCallExpr.getFnName();
        FunctionParams fnParams = functionCallExpr.getParams();

        if (fnParams.isStar() && !fnName.getFunction().equals(FunctionSet.COUNT)) {
            throw new SemanticException("'*' can only be used in conjunction with COUNT: " + functionCallExpr.toSql());
        }

        if (fnName.getFunction().equals(FunctionSet.COUNT)) {
            
            if (functionCallExpr.getChildren().size() > 1 && !fnParams.isDistinct()) {
                throw new SemanticException(
                        "COUNT must have DISTINCT for multiple arguments: " + functionCallExpr.toSql());
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.GROUP_CONCAT)) {
            if (functionCallExpr.getChildren().size() > 2 || functionCallExpr.getChildren().isEmpty()) {
                throw new SemanticException(
                        "group_concat requires one or two parameters: " + functionCallExpr.toSql());
            }

            if (fnParams.isDistinct()) {
                throw new SemanticException("group_concat does not support DISTINCT");
            }

            Expr arg0 = functionCallExpr.getChild(0);
            if (!arg0.getType().isStringType() && !arg0.getType().isNull()) {
                throw new SemanticException(
                        "group_concat requires first parameter to be of getType() STRING: " + functionCallExpr.toSql());
            }

            if (functionCallExpr.getChildren().size() == 2) {
                Expr arg1 = functionCallExpr.getChild(1);
                if (!arg1.getType().isStringType() && !arg1.getType().isNull()) {
                    throw new SemanticException(
                            "group_concat requires second parameter to be of getType() STRING: " +
                                    functionCallExpr.toSql());
                }
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.LAG)
                || fnName.getFunction().equals(FunctionSet.LEAD)) {
            if (!functionCallExpr.isAnalyticFnCall()) {
                throw new SemanticException(fnName.getFunction() + " only used in analytic function");
            } else {
                if (functionCallExpr.getChildren().size() > 2) {
                    if (!functionCallExpr.getChild(2).isConstant()) {
                        throw new SemanticException(
                                "The default parameter (parameter 3) of LAG must be a constant: "
                                        + functionCallExpr.toSql());
                    }
                }
                return;
            }
        }

        if (FunctionSet.onlyAnalyticUsedFunctions.contains(fnName.getFunction())) {
            if (!functionCallExpr.isAnalyticFnCall()) {
                throw new SemanticException(fnName.getFunction() + " only used in analytic function");
            }
        }

        
        Expr arg = functionCallExpr.getChild(0);
        if (arg == null) {
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAY_AGG)) {
            if (fnParams.isDistinct()) {
                throw new SemanticException("array_agg does not support DISTINCT");
            }
            if (arg.getType().isDecimalV3()) {
                throw new SemanticException("array_agg does not support DecimalV3");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAYS_OVERLAP)) {
            if (functionCallExpr.getChildren().size() != 2) {
                throw new SemanticException("arrays_overlap only support 2 parameters");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.ARRAY_FILTER)) {
            if (functionCallExpr.getChildren().size() != 2) {
                throw new SemanticException("array_filter only support 2 parameters");
            }
        }

        if (fnName.getFunction().equals(FunctionSet.RETENTION)) {
            if (!arg.getType().isArrayType()) {
                throw new SemanticException("retention only support Array<BOOLEAN>");
            }
            ArrayType type = (ArrayType) arg.getType();
            if (!type.getItemType().isBoolean()) {
                throw new SemanticException("retention only support Array<BOOLEAN>");
            }
            
        }

        if (fnName.getFunction().equals(FunctionSet.WINDOW_FUNNEL)) {
            Expr modeArg = functionCallExpr.getChild(2);
            if (modeArg instanceof IntLiteral) {
                IntLiteral modeIntLiteral = (IntLiteral) modeArg;
                long modeValue = modeIntLiteral.getValue();
                if (modeValue < 0 || modeValue > 3) {
                    throw new SemanticException("mode argument's range must be [0-3]");
                }
            } else {
                throw new SemanticException("mode argument must be numerical type");
            }

            Expr windowArg = functionCallExpr.getChild(0);
            if (windowArg instanceof IntLiteral) {
                IntLiteral windowIntLiteral = (IntLiteral) windowArg;
                long windowValue = windowIntLiteral.getValue();
                if (windowValue < 0) {
                    throw new SemanticException("window argument must >= 0");
                }
            } else {
                throw new SemanticException("window argument must be numerical type");
            }
        }
        
        if (fnName.getFunction().equals(FunctionSet.MAX_BY)) {
            if (functionCallExpr.getChildren().size() != 2 || functionCallExpr.getChildren().isEmpty()) {
                throw new SemanticException(
                        "max_by requires two parameters: " + functionCallExpr.toSql());
            }
            
            if (functionCallExpr.getChild(0).isConstant() || functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("max_by function args must be column");
            }
            
            fnParams.setIsDistinct(false);  

            Type sortKeyType = functionCallExpr.getChild(1).getType();
            if (!sortKeyType.canApplyToNumeric()) {
                throw new SemanticException(Type.ONLY_METRIC_TYPE_ERROR_MSG);
            }
            
            return;
        }

        
        if ((fnName.getFunction().equals(FunctionSet.SUM)
                || fnName.getFunction().equals(FunctionSet.AVG))
                && ((!arg.getType().isNumericType() && !arg.getType().isBoolean()
                && !arg.getType().isStringType() && !arg.getType().isNull() &&
                !(arg instanceof NullLiteral)) ||
                !arg.getType().canApplyToNumeric())) {
            throw new SemanticException(
                    fnName.getFunction() + " requires a numeric parameter: " + functionCallExpr.toSql());
        }
        if (fnName.getFunction().equals(FunctionSet.SUM_DISTINCT)
                && ((!arg.getType().isNumericType() && !arg.getType().isNull() && !(arg instanceof NullLiteral)) ||
                !arg.getType().canApplyToNumeric())) {
            throw new SemanticException(
                    "SUM_DISTINCT requires a numeric parameter: " + functionCallExpr.toSql());
        }

        if ((fnName.getFunction().equals(FunctionSet.MIN)
                || fnName.getFunction().equals(FunctionSet.MAX)
                || fnName.getFunction().equals(FunctionSet.NDV)
                || fnName.getFunction().equals(FunctionSet.APPROX_COUNT_DISTINCT))
                && !arg.getType().canApplyToNumeric()) {
            throw new SemanticException(Type.ONLY_METRIC_TYPE_ERROR_MSG);
        }

        if ((fnName.getFunction().equals(FunctionSet.BITMAP_UNION_INT) && !arg.getType().isIntegerType())) {
            throw new SemanticException("BITMAP_UNION_INT params only support Integer getType()");
        }

        if (fnName.getFunction().equals(FunctionSet.INTERSECT_COUNT)) {
            if (functionCallExpr.getChildren().size() <= 2) {
                throw new SemanticException("intersect_count(bitmap_column, column_to_filter, filter_values) " +
                        "function requires at least three parameters");
            }

            Type inputType = functionCallExpr.getChild(0).getType();
            if (!inputType.isBitmapType()) {
                throw new SemanticException(
                        "intersect_count function first argument should be of BITMAP getType(), but was " + inputType);
            }

            if (functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("intersect_count function filter_values arg must be column");
            }

            for (int i = 2; i < functionCallExpr.getChildren().size(); i++) {
                if (!functionCallExpr.getChild(i).isConstant()) {
                    throw new SemanticException("intersect_count function filter_values arg must be constant");
                }
            }
            return;
        }

        if (fnName.getFunction().equals(FunctionSet.BITMAP_COUNT)
                || fnName.getFunction().equals(FunctionSet.BITMAP_UNION)
                || fnName.getFunction().equals(FunctionSet.BITMAP_UNION_COUNT)
                || fnName.getFunction().equals(FunctionSet.BITMAP_INTERSECT)) {
            if (functionCallExpr.getChildren().size() != 1) {
                throw new SemanticException(fnName + " function could only have one child");
            }
            Type inputType = functionCallExpr.getChild(0).getType();
            if (!inputType.isBitmapType()) {
                throw new SemanticException(
                        fnName + " function's argument should be of BITMAP getType(), but was " + inputType);
            }
            return;
        }

        if ((fnName.getFunction().equals(FunctionSet.HLL_UNION_AGG)
                || fnName.getFunction().equals(FunctionSet.HLL_UNION)
                || fnName.getFunction().equals(FunctionSet.HLL_CARDINALITY)
                || fnName.getFunction().equals(FunctionSet.HLL_RAW_AGG))
                && !arg.getType().isHllType()) {
            throw new SemanticException(
                    "HLL_UNION_AGG, HLL_RAW_AGG and HLL_CARDINALITY's params must be hll column");
        }

        if (fnName.getFunction().equals(FunctionSet.MIN)
                || fnName.getFunction().equals(FunctionSet.MAX)
                || fnName.getFunction().equals(FunctionSet.NDV)
                || fnName.getFunction().equals(FunctionSet.HLL_UNION_AGG)) {
            fnParams.setIsDistinct(false);  
        }

        if (fnName.getFunction().equals(FunctionSet.PERCENTILE_APPROX)) {
            if (functionCallExpr.getChildren().size() != 2 && functionCallExpr.getChildren().size() != 3) {
                throw new SemanticException("percentile_approx(expr, DOUBLE [, B]) requires two or three parameters");
            }
            if (!functionCallExpr.getChild(1).isConstant()) {
                throw new SemanticException("percentile_approx requires second parameter must be a constant : "
                        + functionCallExpr.toSql());
            }
            if (functionCallExpr.getChildren().size() == 3) {
                if (!functionCallExpr.getChild(2).isConstant()) {
                    throw new SemanticException("percentile_approx requires the third parameter must be a constant : "
                            + functionCallExpr.toSql());
                }
            }
        }
    }