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

marong pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-gluten.git


The following commit(s) were added to refs/heads/main by this push:
     new 291f08429 [GLUTEN-5840][VL] Fix udaf register simple intermediate type 
(#5876)
291f08429 is described below

commit 291f0842905b704db6f303e88295280e383d0a38
Author: Rong Ma <[email protected]>
AuthorDate: Tue May 28 14:25:38 2024 +0800

    [GLUTEN-5840][VL] Fix udaf register simple intermediate type (#5876)
---
 .../apache/spark/sql/expression/UDFResolver.scala  |  14 +-
 .../apache/gluten/expression/VeloxUdfSuite.scala   |   5 +-
 cpp/velox/udf/examples/MyUDAF.cc                   | 366 +++++++++++++++++----
 cpp/velox/udf/examples/MyUDF.cc                    |  30 +-
 cpp/velox/udf/examples/UdfCommon.h                 |  53 +++
 docs/developers/VeloxUDF.md                        |   7 +-
 6 files changed, 380 insertions(+), 95 deletions(-)

diff --git 
a/backends-velox/src/main/scala/org/apache/spark/sql/expression/UDFResolver.scala
 
b/backends-velox/src/main/scala/org/apache/spark/sql/expression/UDFResolver.scala
index ec98e98f1..915fc5545 100644
--- 
a/backends-velox/src/main/scala/org/apache/spark/sql/expression/UDFResolver.scala
+++ 
b/backends-velox/src/main/scala/org/apache/spark/sql/expression/UDFResolver.scala
@@ -175,12 +175,16 @@ object UDFResolver extends Logging {
       intermediateTypes: ExpressionType,
       variableArity: Boolean): Unit = {
     assert(argTypes.dataType.isInstanceOf[StructType])
-    assert(intermediateTypes.dataType.isInstanceOf[StructType])
 
-    val aggBufferAttributes =
-      
intermediateTypes.dataType.asInstanceOf[StructType].fields.zipWithIndex.map {
-        case (f, index) =>
-          AttributeReference(s"inter_$index", f.dataType, f.nullable)()
+    val aggBufferAttributes: Seq[AttributeReference] =
+      intermediateTypes.dataType match {
+        case StructType(fields) =>
+          fields.zipWithIndex.map {
+            case (f, index) =>
+              AttributeReference(s"agg_inter_$index", f.dataType, f.nullable)()
+          }
+        case t =>
+          Seq(AttributeReference(s"agg_inter", t)())
       }
 
     val v =
diff --git 
a/backends-velox/src/test/scala/org/apache/gluten/expression/VeloxUdfSuite.scala
 
b/backends-velox/src/test/scala/org/apache/gluten/expression/VeloxUdfSuite.scala
index 4d2f9fae3..534a8d9f1 100644
--- 
a/backends-velox/src/test/scala/org/apache/gluten/expression/VeloxUdfSuite.scala
+++ 
b/backends-velox/src/test/scala/org/apache/gluten/expression/VeloxUdfSuite.scala
@@ -93,12 +93,13 @@ abstract class VeloxUdfSuite extends GlutenQueryTest with 
SQLHelper {
                          |  myavg(1),
                          |  myavg(1L),
                          |  myavg(cast(1.0 as float)),
-                         |  myavg(cast(1.0 as double))
+                         |  myavg(cast(1.0 as double)),
+                         |  mycount_if(true)
                          |""".stripMargin)
     df.collect()
     assert(
       df.collect()
-        .sameElements(Array(Row(1.0, 1.0, 1.0, 1.0))))
+        .sameElements(Array(Row(1.0, 1.0, 1.0, 1.0, 1L))))
   }
 }
 
diff --git a/cpp/velox/udf/examples/MyUDAF.cc b/cpp/velox/udf/examples/MyUDAF.cc
index e6c4b1fea..710bce53a 100644
--- a/cpp/velox/udf/examples/MyUDAF.cc
+++ b/cpp/velox/udf/examples/MyUDAF.cc
@@ -20,19 +20,22 @@
 #include <velox/functions/Macros.h>
 #include <velox/functions/Registerer.h>
 #include <velox/functions/lib/aggregates/AverageAggregateBase.h>
-#include <iostream>
+
 #include "udf/Udaf.h"
+#include "udf/examples/UdfCommon.h"
 
 using namespace facebook::velox;
 using namespace facebook::velox::exec;
 
 namespace {
 
+static const char* kBoolean = "boolean";
 static const char* kInteger = "int";
 static const char* kBigInt = "bigint";
 static const char* kFloat = "float";
 static const char* kDouble = "double";
 
+namespace myavg {
 // Copied from velox/exec/tests/SimpleAverageAggregate.cpp
 
 // Implementation of the average aggregation function through the
@@ -98,84 +101,321 @@ class AverageAggregate {
   };
 };
 
-exec::AggregateRegistrationResult registerSimpleAverageAggregate(const 
std::string& name) {
-  std::vector<std::shared_ptr<exec::AggregateFunctionSignature>> signatures;
+class MyAvgRegisterer final : public gluten::UdafRegisterer {
+  int getNumUdaf() override {
+    return 4;
+  }
+
+  void populateUdafEntries(int& index, gluten::UdafEntry* udafEntries) 
override {
+    for (const auto& argTypes : {myAvgArg1_, myAvgArg2_, myAvgArg3_, 
myAvgArg4_}) {
+      udafEntries[index++] = {name_.c_str(), kDouble, 1, argTypes, 
myAvgIntermediateType_};
+    }
+  }
+
+  void registerSignatures() override {
+    registerSimpleAverageAggregate();
+  }
+
+ private:
+  exec::AggregateRegistrationResult registerSimpleAverageAggregate() {
+    std::vector<std::shared_ptr<exec::AggregateFunctionSignature>> signatures;
+
+    for (const auto& inputType : {"smallint", "integer", "bigint", "double"}) {
+      signatures.push_back(exec::AggregateFunctionSignatureBuilder()
+                               .returnType("double")
+                               .intermediateType("row(double,bigint)")
+                               .argumentType(inputType)
+                               .build());
+    }
 
-  for (const auto& inputType : {"smallint", "integer", "bigint", "double"}) {
     signatures.push_back(exec::AggregateFunctionSignatureBuilder()
-                             .returnType("double")
+                             .returnType("real")
                              .intermediateType("row(double,bigint)")
-                             .argumentType(inputType)
+                             .argumentType("real")
                              .build());
-  }
 
-  signatures.push_back(exec::AggregateFunctionSignatureBuilder()
-                           .returnType("real")
-                           .intermediateType("row(double,bigint)")
-                           .argumentType("real")
-                           .build());
-
-  return exec::registerAggregateFunction(
-      name,
-      std::move(signatures),
-      [name](
-          core::AggregationNode::Step step,
-          const std::vector<TypePtr>& argTypes,
-          const TypePtr& resultType,
-          const core::QueryConfig& /*config*/) -> 
std::unique_ptr<exec::Aggregate> {
-        VELOX_CHECK_LE(argTypes.size(), 1, "{} takes at most one argument", 
name);
-        auto inputType = argTypes[0];
-        if (exec::isRawInput(step)) {
-          switch (inputType->kind()) {
-            case TypeKind::SMALLINT:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int16_t>>>(resultType);
-            case TypeKind::INTEGER:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int32_t>>>(resultType);
-            case TypeKind::BIGINT:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int64_t>>>(resultType);
-            case TypeKind::REAL:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<float>>>(resultType);
-            case TypeKind::DOUBLE:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<double>>>(resultType);
-            default:
-              VELOX_FAIL("Unknown input type for {} aggregation {}", name, 
inputType->kindName());
-          }
-        } else {
-          switch (resultType->kind()) {
-            case TypeKind::REAL:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<float>>>(resultType);
-            case TypeKind::DOUBLE:
-            case TypeKind::ROW:
-              return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<double>>>(resultType);
-            default:
-              VELOX_FAIL("Unsupported result type for final aggregation: {}", 
resultType->kindName());
+    return exec::registerAggregateFunction(
+        name_,
+        std::move(signatures),
+        [this](
+            core::AggregationNode::Step step,
+            const std::vector<TypePtr>& argTypes,
+            const TypePtr& resultType,
+            const core::QueryConfig& /*config*/) -> 
std::unique_ptr<exec::Aggregate> {
+          VELOX_CHECK_LE(argTypes.size(), 1, "{} takes at most one argument", 
name_);
+          auto inputType = argTypes[0];
+          if (exec::isRawInput(step)) {
+            switch (inputType->kind()) {
+              case TypeKind::SMALLINT:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int16_t>>>(resultType);
+              case TypeKind::INTEGER:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int32_t>>>(resultType);
+              case TypeKind::BIGINT:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<int64_t>>>(resultType);
+              case TypeKind::REAL:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<float>>>(resultType);
+              case TypeKind::DOUBLE:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<double>>>(resultType);
+              default:
+                VELOX_FAIL("Unknown input type for {} aggregation {}", name_, 
inputType->kindName());
+            }
+          } else {
+            switch (resultType->kind()) {
+              case TypeKind::REAL:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<float>>>(resultType);
+              case TypeKind::DOUBLE:
+              case TypeKind::ROW:
+                return 
std::make_unique<SimpleAggregateAdapter<AverageAggregate<double>>>(resultType);
+              default:
+                VELOX_FAIL("Unsupported result type for final aggregation: 
{}", resultType->kindName());
+            }
           }
+        },
+        true /*registerCompanionFunctions*/,
+        true /*overwrite*/);
+  }
+
+  const std::string name_ = "myavg";
+  const char* myAvgArg1_[1] = {kInteger};
+  const char* myAvgArg2_[1] = {kBigInt};
+  const char* myAvgArg3_[1] = {kFloat};
+  const char* myAvgArg4_[1] = {kDouble};
+
+  const char* myAvgIntermediateType_ = "struct<a:double,b:bigint>";
+};
+} // namespace myavg
+
+namespace mycountif {
+
+// Copied from velox/functions/prestosql/aggregates/CountIfAggregate.cpp
+class CountIfAggregate : public exec::Aggregate {
+ public:
+  explicit CountIfAggregate() : exec::Aggregate(BIGINT()) {}
+
+  int32_t accumulatorFixedWidthSize() const override {
+    return sizeof(int64_t);
+  }
+
+  void extractAccumulators(char** groups, int32_t numGroups, VectorPtr* 
result) override {
+    extractValues(groups, numGroups, result);
+  }
+
+  void extractValues(char** groups, int32_t numGroups, VectorPtr* result) 
override {
+    auto* vector = (*result)->as<FlatVector<int64_t>>();
+    VELOX_CHECK(vector);
+    vector->resize(numGroups);
+
+    auto* rawValues = vector->mutableRawValues();
+    for (vector_size_t i = 0; i < numGroups; ++i) {
+      rawValues[i] = *value<int64_t>(groups[i]);
+    }
+  }
+
+  void addRawInput(
+      char** groups,
+      const SelectivityVector& rows,
+      const std::vector<VectorPtr>& args,
+      bool /*mayPushdown*/) override {
+    DecodedVector decoded(*args[0], rows);
+
+    if (decoded.isConstantMapping()) {
+      if (decoded.isNullAt(0)) {
+        return;
+      }
+      if (decoded.valueAt<bool>(0)) {
+        rows.applyToSelected([&](vector_size_t i) { addToGroup(groups[i], 1); 
});
+      }
+    } else if (decoded.mayHaveNulls()) {
+      rows.applyToSelected([&](vector_size_t i) {
+        if (decoded.isNullAt(i)) {
+          return;
+        }
+        if (decoded.valueAt<bool>(i)) {
+          addToGroup(groups[i], 1);
         }
-      },
-      true /*registerCompanionFunctions*/,
-      true /*overwrite*/);
+      });
+    } else {
+      rows.applyToSelected([&](vector_size_t i) {
+        if (decoded.valueAt<bool>(i)) {
+          addToGroup(groups[i], 1);
+        }
+      });
+    }
+  }
+
+  void addIntermediateResults(
+      char** groups,
+      const SelectivityVector& rows,
+      const std::vector<VectorPtr>& args,
+      bool /*mayPushdown*/) override {
+    DecodedVector decoded(*args[0], rows);
+
+    if (decoded.isConstantMapping()) {
+      auto numTrue = decoded.valueAt<int64_t>(0);
+      rows.applyToSelected([&](vector_size_t i) { addToGroup(groups[i], 
numTrue); });
+      return;
+    }
+
+    rows.applyToSelected([&](vector_size_t i) {
+      auto numTrue = decoded.valueAt<int64_t>(i);
+      addToGroup(groups[i], numTrue);
+    });
+  }
+
+  void addSingleGroupRawInput(
+      char* group,
+      const SelectivityVector& rows,
+      const std::vector<VectorPtr>& args,
+      bool /*mayPushdown*/) override {
+    DecodedVector decoded(*args[0], rows);
+
+    // Constant mapping - check once and add number of selected rows if true.
+    if (decoded.isConstantMapping()) {
+      if (!decoded.isNullAt(0)) {
+        auto isTrue = decoded.valueAt<bool>(0);
+        if (isTrue) {
+          addToGroup(group, rows.countSelected());
+        }
+      }
+      return;
+    }
+
+    int64_t numTrue = 0;
+    if (decoded.mayHaveNulls()) {
+      rows.applyToSelected([&](vector_size_t i) {
+        if (decoded.isNullAt(i)) {
+          return;
+        }
+        if (decoded.valueAt<bool>(i)) {
+          ++numTrue;
+        }
+      });
+    } else {
+      rows.applyToSelected([&](vector_size_t i) {
+        if (decoded.valueAt<bool>(i)) {
+          ++numTrue;
+        }
+      });
+    }
+    addToGroup(group, numTrue);
+  }
+
+  void addSingleGroupIntermediateResults(
+      char* group,
+      const SelectivityVector& rows,
+      const std::vector<VectorPtr>& args,
+      bool /*mayPushdown*/) override {
+    auto arg = args[0]->as<SimpleVector<int64_t>>();
+
+    int64_t numTrue = 0;
+    rows.applyToSelected([&](auto row) { numTrue += arg->valueAt(row); });
+
+    addToGroup(group, numTrue);
+  }
+
+ protected:
+  void initializeNewGroupsInternal(char** groups, folly::Range<const 
vector_size_t*> indices) override {
+    for (auto i : indices) {
+      *value<int64_t>(groups[i]) = 0;
+    }
+  }
+
+ private:
+  inline void addToGroup(char* group, int64_t numTrue) {
+    *value<int64_t>(group) += numTrue;
+  }
+};
+
+class MyCountIfRegisterer final : public gluten::UdafRegisterer {
+  int getNumUdaf() override {
+    return 1;
+  }
+
+  void populateUdafEntries(int& index, gluten::UdafEntry* udafEntries) 
override {
+    udafEntries[index++] = {name_.c_str(), kBigInt, 1, myCountIfArg_, kBigInt};
+  }
+
+  void registerSignatures() override {
+    registerCountIfAggregate();
+  }
+
+ private:
+  void registerCountIfAggregate() {
+    std::vector<std::shared_ptr<exec::AggregateFunctionSignature>> signatures{
+        exec::AggregateFunctionSignatureBuilder()
+            .returnType("bigint")
+            .intermediateType("bigint")
+            .argumentType("boolean")
+            .build(),
+    };
+
+    exec::registerAggregateFunction(
+        name_,
+        std::move(signatures),
+        [this](
+            core::AggregationNode::Step step,
+            std::vector<TypePtr> argTypes,
+            const TypePtr& /*resultType*/,
+            const core::QueryConfig& /*config*/) -> 
std::unique_ptr<exec::Aggregate> {
+          VELOX_CHECK_EQ(argTypes.size(), 1, "{} takes one argument", name_);
+
+          auto isPartial = exec::isRawInput(step);
+          if (isPartial) {
+            VELOX_CHECK_EQ(argTypes[0]->kind(), TypeKind::BOOLEAN, "{} 
function only accepts boolean parameter", name_);
+          }
+
+          return std::make_unique<CountIfAggregate>();
+        },
+        {false /*orderSensitive*/},
+        true,
+        true);
+  }
+
+  const std::string name_ = "mycount_if";
+  const char* myCountIfArg_[1] = {kBoolean};
+};
+} // namespace mycountif
+
+std::vector<std::shared_ptr<gluten::UdafRegisterer>>& globalRegisters() {
+  static std::vector<std::shared_ptr<gluten::UdafRegisterer>> registerers;
+  return registerers;
 }
-} // namespace
 
-const int kNumMyUdaf = 4;
+void setupRegisterers() {
+  static bool inited = false;
+  if (inited) {
+    return;
+  }
+  auto& registerers = globalRegisters();
+  registerers.push_back(std::make_shared<myavg::MyAvgRegisterer>());
+  registerers.push_back(std::make_shared<mycountif::MyCountIfRegisterer>());
+  inited = true;
+}
+} // namespace
 
 DEFINE_GET_NUM_UDAF {
-  return kNumMyUdaf;
+  setupRegisterers();
+
+  int numUdf = 0;
+  for (const auto& registerer : globalRegisters()) {
+    numUdf += registerer->getNumUdaf();
+  }
+  return numUdf;
 }
 
-const char* myAvgArg1[] = {kInteger};
-const char* myAvgArg2[] = {kBigInt};
-const char* myAvgArg3[] = {kFloat};
-const char* myAvgArg4[] = {kDouble};
-const char* myAvgIntermediateType = "struct<a:double,b:bigint>";
 DEFINE_GET_UDAF_ENTRIES {
+  setupRegisterers();
+
   int index = 0;
-  udafEntries[index++] = {"myavg", kDouble, 1, myAvgArg1, 
myAvgIntermediateType};
-  udafEntries[index++] = {"myavg", kDouble, 1, myAvgArg2, 
myAvgIntermediateType};
-  udafEntries[index++] = {"myavg", kDouble, 1, myAvgArg3, 
myAvgIntermediateType};
-  udafEntries[index++] = {"myavg", kDouble, 1, myAvgArg4, 
myAvgIntermediateType};
+  for (const auto& registerer : globalRegisters()) {
+    registerer->populateUdafEntries(index, udafEntries);
+  }
 }
 
 DEFINE_REGISTER_UDAF {
-  registerSimpleAverageAggregate("myavg");
+  setupRegisterers();
+
+  for (const auto& registerer : globalRegisters()) {
+    registerer->registerSignatures();
+  }
 }
diff --git a/cpp/velox/udf/examples/MyUDF.cc b/cpp/velox/udf/examples/MyUDF.cc
index 88bc3ad85..ee20ca39d 100644
--- a/cpp/velox/udf/examples/MyUDF.cc
+++ b/cpp/velox/udf/examples/MyUDF.cc
@@ -20,28 +20,17 @@
 #include <velox/functions/Registerer.h>
 #include <iostream>
 #include "udf/Udf.h"
+#include "udf/examples/UdfCommon.h"
 
 using namespace facebook::velox;
 using namespace facebook::velox::exec;
 
+namespace {
+
 static const char* kInteger = "int";
 static const char* kBigInt = "bigint";
 static const char* kDate = "date";
 
-class UdfRegisterer {
- public:
-  ~UdfRegisterer() = default;
-
-  // Returns the number of UDFs in populateUdfEntries.
-  virtual int getNumUdf() = 0;
-
-  // Populate the udfEntries, starting at the given index.
-  virtual void populateUdfEntries(int& index, gluten::UdfEntry* udfEntries) = 
0;
-
-  // Register all function signatures to velox.
-  virtual void registerSignatures() = 0;
-};
-
 namespace myudf {
 
 template <TypeKind Kind>
@@ -106,7 +95,7 @@ static 
std::shared_ptr<facebook::velox::exec::VectorFunction> makePlusConstant(
 // signatures:
 //    bigint -> bigint
 // type: VectorFunction
-class MyUdf1Registerer final : public UdfRegisterer {
+class MyUdf1Registerer final : public gluten::UdfRegisterer {
  public:
   int getNumUdf() override {
     return 1;
@@ -135,7 +124,7 @@ class MyUdf1Registerer final : public UdfRegisterer {
 //    integer -> integer
 //    bigint -> bigint
 // type: StatefulVectorFunction
-class MyUdf2Registerer final : public UdfRegisterer {
+class MyUdf2Registerer final : public gluten::UdfRegisterer {
  public:
   int getNumUdf() override {
     return 2;
@@ -167,7 +156,7 @@ class MyUdf2Registerer final : public UdfRegisterer {
 //    [integer,] ... -> integer
 //    bigint, [bigint,] ... -> bigint
 // type: StatefulVectorFunction with variable arity
-class MyUdf3Registerer final : public UdfRegisterer {
+class MyUdf3Registerer final : public gluten::UdfRegisterer {
  public:
   int getNumUdf() override {
     return 2;
@@ -215,7 +204,7 @@ struct MyDateSimpleFunction {
 // signatures:
 //    date, integer -> bigint
 // type: SimpleFunction
-class MyDateRegisterer final : public UdfRegisterer {
+class MyDateRegisterer final : public gluten::UdfRegisterer {
  public:
   int getNumUdf() override {
     return 1;
@@ -235,8 +224,8 @@ class MyDateRegisterer final : public UdfRegisterer {
 };
 } // namespace mydate
 
-std::vector<std::shared_ptr<UdfRegisterer>>& globalRegisters() {
-  static std::vector<std::shared_ptr<UdfRegisterer>> registerers;
+std::vector<std::shared_ptr<gluten::UdfRegisterer>>& globalRegisters() {
+  static std::vector<std::shared_ptr<gluten::UdfRegisterer>> registerers;
   return registerers;
 }
 
@@ -252,6 +241,7 @@ void setupRegisterers() {
   registerers.push_back(std::make_shared<mydate::MyDateRegisterer>());
   inited = true;
 }
+} // namespace
 
 DEFINE_GET_NUM_UDF {
   setupRegisterers();
diff --git a/cpp/velox/udf/examples/UdfCommon.h 
b/cpp/velox/udf/examples/UdfCommon.h
new file mode 100644
index 000000000..a68c47460
--- /dev/null
+++ b/cpp/velox/udf/examples/UdfCommon.h
@@ -0,0 +1,53 @@
+/*
+ * 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 "udf/Udaf.h"
+#include "udf/Udf.h"
+
+namespace gluten {
+
+class UdfRegisterer {
+ public:
+  ~UdfRegisterer() = default;
+
+  // Returns the number of UDFs in populateUdfEntries.
+  virtual int getNumUdf() = 0;
+
+  // Populate the udfEntries, starting at the given index.
+  virtual void populateUdfEntries(int& index, gluten::UdfEntry* udfEntries) = 
0;
+
+  // Register all function signatures to velox.
+  virtual void registerSignatures() = 0;
+};
+
+class UdafRegisterer {
+ public:
+  ~UdafRegisterer() = default;
+
+  // Returns the number of UDFs in populateUdafEntries.
+  virtual int getNumUdaf() = 0;
+
+  // Populate the udfEntries, starting at the given index.
+  virtual void populateUdafEntries(int& index, gluten::UdafEntry* udafEntries) 
= 0;
+
+  // Register all function signatures to velox.
+  virtual void registerSignatures() = 0;
+};
+
+} // namespace gluten
\ No newline at end of file
diff --git a/docs/developers/VeloxUDF.md b/docs/developers/VeloxUDF.md
index b88c4de15..c896fd672 100644
--- a/docs/developers/VeloxUDF.md
+++ b/docs/developers/VeloxUDF.md
@@ -137,13 +137,10 @@ You can also specify the local or HDFS URIs to the UDF 
libraries or archives. Lo
 ## Try the example
 
 We provided Velox UDF examples in file 
[MyUDF.cc](../../cpp/velox/udf/examples/MyUDF.cc) and UDAF examples in file 
[MyUDAF.cc](../../cpp/velox/udf/examples/MyUDAF.cc).
-You need to build the gluten cpp project with `--build_example=ON` to get the 
example libraries.
+You need to build the gluten project with `--build_example=ON` to get the 
example libraries.
 
 ```shell
-## compile Gluten cpp module
-cd /path/to/gluten/cpp
-## if you use custom velox_home, make sure specified here by --velox_home
-./compile.sh --build_velox_backend=ON --build_examples=ON
+./dev/buildbundle-veloxbe.sh --build_examples=ON
 ```
 
 Then, you can find the example libraries at 
/path/to/gluten/cpp/build/velox/udf/examples/


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to