This is an automated email from the ASF dual-hosted git repository.
loneylee 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 07b8679a5c [GLUTEN-8748][CH] Support function
monotonically_increasing_id (#8771)
07b8679a5c is described below
commit 07b8679a5c9240441978b8b18c9da311e6eeba4d
Author: Shuai li <[email protected]>
AuthorDate: Wed Feb 19 15:35:38 2025 +0800
[GLUTEN-8748][CH] Support function monotonically_increasing_id (#8771)
* [GLUTEN-8748][CH] Support function monotonically_increasing_id
---
.../vectorized/CHNativeExpressionEvaluator.java | 14 ++-
.../vectorized/ExpressionEvaluatorJniWrapper.java | 3 +-
.../backendsapi/clickhouse/CHIteratorApi.scala | 20 +++-
.../execution/NativeFileScanColumnarRDD.scala | 3 +-
.../org/apache/gluten/utils/CHExpressionUtil.scala | 1 -
.../metrics/GlutenClickHouseMetricsUTUtils.scala | 3 +-
.../SparkFunctionMonotonicallyIncreasingID.cpp | 106 +++++++++++++++++++++
cpp-ch/local-engine/Parser/ParserContext.cpp | 8 +-
cpp-ch/local-engine/Parser/ParserContext.h | 7 +-
.../monotonicallyIncreasingId.cpp | 49 ++++++++++
cpp-ch/local-engine/local_engine_jni.cpp | 5 +-
11 files changed, 201 insertions(+), 18 deletions(-)
diff --git
a/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/CHNativeExpressionEvaluator.java
b/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/CHNativeExpressionEvaluator.java
index 12b79a54ce..31bb2e16fb 100644
---
a/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/CHNativeExpressionEvaluator.java
+++
b/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/CHNativeExpressionEvaluator.java
@@ -64,7 +64,8 @@ public class CHNativeExpressionEvaluator extends
ExpressionEvaluatorJniWrapper {
byte[] wsPlan,
byte[][] splitInfo,
List<ColumnarNativeIterator> iterList,
- boolean materializeInput) {
+ boolean materializeInput,
+ int partitionIndex) {
CHThreadGroup.registerNewThreadGroup();
long handle =
nativeCreateKernelWithIterator(
@@ -72,13 +73,17 @@ public class CHNativeExpressionEvaluator extends
ExpressionEvaluatorJniWrapper {
splitInfo,
iterList.toArray(new ColumnarNativeIterator[0]),
ConfigUtil.serialize(getNativeBackendConf()),
- materializeInput);
+ materializeInput,
+ partitionIndex);
return createBatchIterator(handle);
}
// Only for UT.
public static BatchIterator createKernelWithBatchIterator(
- byte[] wsPlan, byte[][] splitInfo, List<ColumnarNativeIterator>
iterList) {
+ byte[] wsPlan,
+ byte[][] splitInfo,
+ List<ColumnarNativeIterator> iterList,
+ int partitionIndex) {
CHThreadGroup.registerNewThreadGroup();
long handle =
nativeCreateKernelWithIterator(
@@ -86,7 +91,8 @@ public class CHNativeExpressionEvaluator extends
ExpressionEvaluatorJniWrapper {
splitInfo,
iterList.toArray(new ColumnarNativeIterator[0]),
ConfigUtil.serialize(getNativeBackendConf()),
- false);
+ false,
+ partitionIndex);
return createBatchIterator(handle);
}
diff --git
a/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/ExpressionEvaluatorJniWrapper.java
b/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/ExpressionEvaluatorJniWrapper.java
index 76fddcafdd..20a4241798 100644
---
a/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/ExpressionEvaluatorJniWrapper.java
+++
b/backends-clickhouse/src/main/java/org/apache/gluten/vectorized/ExpressionEvaluatorJniWrapper.java
@@ -41,7 +41,8 @@ public class ExpressionEvaluatorJniWrapper {
byte[][] splitInfo,
ColumnarNativeIterator[] batchItr,
byte[] confArray,
- boolean materializeInput);
+ boolean materializeInput,
+ int partitionIndex);
public static native void updateQueryRuntimeSettings(byte[] settings);
}
diff --git
a/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHIteratorApi.scala
b/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHIteratorApi.scala
index a4e641a98c..308b3fa4f5 100644
---
a/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHIteratorApi.scala
+++
b/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHIteratorApi.scala
@@ -73,6 +73,7 @@ class CHIteratorApi extends IteratorApi with Logging with
LogLevelUtil {
splitInfoByteArray: Array[Array[Byte]],
wsPlan: Array[Byte],
materializeInput: Boolean,
+ partitionIndex: Int,
inputIterators: Seq[Iterator[ColumnarBatch]]): BatchIterator = {
/** Generate closeable ColumnBatch iterator. */
@@ -88,7 +89,8 @@ class CHIteratorApi extends IteratorApi with Logging with
LogLevelUtil {
wsPlan,
splitInfoByteArray,
listIterator,
- materializeInput
+ materializeInput,
+ partitionIndex
)
}
@@ -290,7 +292,13 @@ class CHIteratorApi extends IteratorApi with Logging with
LogLevelUtil {
pipelineTime,
updateNativeMetrics,
Some(updateInputMetrics),
- createNativeIterator(splitInfoByteArray, wsPlan, materializeInput,
inputIterators))
+ createNativeIterator(
+ splitInfoByteArray,
+ wsPlan,
+ materializeInput,
+ partitionIndex,
+ inputIterators)
+ )
)
}
@@ -318,7 +326,13 @@ class CHIteratorApi extends IteratorApi with Logging with
LogLevelUtil {
pipelineTime,
updateNativeMetrics,
None,
- createNativeIterator(splitInfoByteArray, wsPlan, materializeInput,
inputIterators))
+ createNativeIterator(
+ splitInfoByteArray,
+ wsPlan,
+ materializeInput,
+ partitionIndex,
+ inputIterators)
+ )
}
}
diff --git
a/backends-clickhouse/src/main/scala/org/apache/gluten/execution/NativeFileScanColumnarRDD.scala
b/backends-clickhouse/src/main/scala/org/apache/gluten/execution/NativeFileScanColumnarRDD.scala
index fe29b6d2f2..abe8ea0b94 100644
---
a/backends-clickhouse/src/main/scala/org/apache/gluten/execution/NativeFileScanColumnarRDD.scala
+++
b/backends-clickhouse/src/main/scala/org/apache/gluten/execution/NativeFileScanColumnarRDD.scala
@@ -54,7 +54,8 @@ class NativeFileScanColumnarRDD(
inputPartition.plan,
splitInfoByteArray,
inBatchIters,
- false
+ false,
+ split.index
)
}
TaskContext
diff --git
a/backends-clickhouse/src/main/scala/org/apache/gluten/utils/CHExpressionUtil.scala
b/backends-clickhouse/src/main/scala/org/apache/gluten/utils/CHExpressionUtil.scala
index dc2d8716b2..4a9ce71c79 100644
---
a/backends-clickhouse/src/main/scala/org/apache/gluten/utils/CHExpressionUtil.scala
+++
b/backends-clickhouse/src/main/scala/org/apache/gluten/utils/CHExpressionUtil.scala
@@ -186,7 +186,6 @@ object CHExpressionUtil {
DECODE -> EncodeDecodeValidator(),
ENCODE -> EncodeDecodeValidator(),
DATE_FROM_UNIX_DATE -> DefaultValidator(),
- MONOTONICALLY_INCREASING_ID -> DefaultValidator(),
SPARK_PARTITION_ID -> DefaultValidator(),
AT_LEAST_N_NON_NULLS -> DefaultValidator(),
URL_DECODE -> DefaultValidator(),
diff --git
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/metrics/GlutenClickHouseMetricsUTUtils.scala
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/metrics/GlutenClickHouseMetricsUTUtils.scala
index 52a68e2d62..3a2be45ff8 100644
---
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/metrics/GlutenClickHouseMetricsUTUtils.scala
+++
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/metrics/GlutenClickHouseMetricsUTUtils.scala
@@ -47,7 +47,8 @@ object GlutenClickHouseMetricsUTUtils {
val resIter = CHNativeExpressionEvaluator.createKernelWithBatchIterator(
substraitPlan.toByteArray,
new Array[Array[Byte]](0),
- inBatchIters)
+ inBatchIters,
+ 0)
val iter = new Iterator[Any] {
private var outputRowCount = 0L
private var outputVectorCount = 0L
diff --git
a/cpp-ch/local-engine/Functions/SparkFunctionMonotonicallyIncreasingID.cpp
b/cpp-ch/local-engine/Functions/SparkFunctionMonotonicallyIncreasingID.cpp
new file mode 100644
index 0000000000..6c3e654bf8
--- /dev/null
+++ b/cpp-ch/local-engine/Functions/SparkFunctionMonotonicallyIncreasingID.cpp
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <atomic>
+#include <Columns/ColumnsNumber.h>
+#include <DataTypes/DataTypesNumber.h>
+#include <Functions/FunctionFactory.h>
+#include <Functions/IFunction.h>
+
+namespace DB
+{
+namespace ErrorCodes
+{
+extern const int ILLEGAL_TYPE_OF_ARGUMENT;
+extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
+}
+}
+
+namespace local_engine
+{
+/**
+ * Returns monotonically increasing 64-bit integers. The generated ID is
guaranteed
+ * to be monotonically increasing and unique, but not consecutive. The
current implementation
+ * puts the partition ID in the upper 31 bits, and the lower 33 bits
represent the record number
+ * within each partition. The assumption is that the data frame has less
than 1 billion
+ * partitions, and each partition has less than 8 billion records.
+ * The function is non-deterministic because its result depends on
partition IDs.
+ */
+class SparkFunctionMonotonicallyIncreasingID : public DB::IFunction
+{
+public:
+ static constexpr auto name = "sparkMonotonicallyIncreasingId";
+ static DB::FunctionPtr create(DB::ContextPtr) { return
std::make_shared<SparkFunctionMonotonicallyIncreasingID>(); }
+
+ String getName() const override { return name; }
+
+ bool isStateful() const override { return true; }
+
+ bool isSuitableForShortCircuitArgumentsExecution(const
DB::DataTypesWithConstInfo & /*arguments*/) const override { return false; }
+
+ size_t getNumberOfArguments() const override { return 1; }
+ DB::DataTypePtr getReturnTypeImpl(const DB::DataTypes & arguments) const
override
+ {
+ if (arguments.size() != 1)
+ throw DB::Exception(
+ DB::ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
+ "Number of arguments for function {} doesn't match: passed {},
should be 1.",
+ getName(),
+ arguments.size());
+
+ if (!isInteger(arguments[0]))
+ throw DB::Exception(DB::ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
"Argument for function {} must be integer", getName());
+
+ return std::make_shared<DB::DataTypeInt64>();
+ }
+
+ DB::ColumnPtr
+ executeImplDryRun(const DB::ColumnsWithTypeAndName &, const
DB::DataTypePtr & result_type, size_t input_rows_count) const override
+ {
+ return DB::ColumnInt64::create(input_rows_count);
+ }
+
+ DB::ColumnPtr
+ executeImpl(const DB::ColumnsWithTypeAndName & arguments, const
DB::DataTypePtr & result_type, size_t input_rows_count) const override
+ {
+ const auto partitionIndex = arguments[0].column->getInt(0);
+ const auto partitionMask = partitionIndex << 33;
+
+ auto result = result_type->createColumn();
+ result->reserve(input_rows_count);
+
+ for (size_t i = 0; i < input_rows_count; ++i)
+ {
+ auto a=partitionMask + count.load(std::memory_order_relaxed);
+ result->insert(a);
+ count.fetch_add(1, std::memory_order_relaxed);
+ }
+
+ return result;
+ }
+
+private:
+ mutable std::atomic<size_t> count{0};
+};
+
+
+REGISTER_FUNCTION(SparkFunctionMonotonicallyIncreasingID)
+{
+ factory.registerFunction<SparkFunctionMonotonicallyIncreasingID>();
+}
+
+}
\ No newline at end of file
diff --git a/cpp-ch/local-engine/Parser/ParserContext.cpp
b/cpp-ch/local-engine/Parser/ParserContext.cpp
index 3e5d6fffe7..884d8152fc 100644
--- a/cpp-ch/local-engine/Parser/ParserContext.cpp
+++ b/cpp-ch/local-engine/Parser/ParserContext.cpp
@@ -39,11 +39,13 @@ void ParserContext::addSelfDefinedFunctionMapping()
legacy_function_mapping[std::to_string(SelfDefinedFunctionReference::GET_JSON_OBJECT)]
= sig.signature;
}
-ParserContextPtr ParserContext::build(DB::ContextPtr context_, const
std::unordered_map<String, String> & function_mapping_)
+ParserContextPtr
+ParserContext::build(DB::ContextPtr context_, const std::unordered_map<String,
String> & function_mapping_, const size_t & partition_index_)
{
auto res = std::make_shared<ParserContext>();
res->query_context = context_;
res->legacy_function_mapping = function_mapping_;
+ res->partition_index = partition_index_;
auto & function_mapping = res->function_mapping;
for (const auto & fm : function_mapping_)
{
@@ -66,7 +68,7 @@ ParserContextPtr ParserContext::build(DB::ContextPtr context_)
return res;
}
-ParserContextPtr ParserContext::build(DB::ContextPtr context_, const
substrait::Plan & plan_)
+ParserContextPtr ParserContext::build(DB::ContextPtr context_, const
substrait::Plan & plan_, const size_t & partition_index_)
{
std::unordered_map<String, String> function_mapping;
for (const auto & extension : plan_.extensions())
@@ -77,7 +79,7 @@ ParserContextPtr ParserContext::build(DB::ContextPtr
context_, const substrait::
std::to_string(extension.extension_function().function_anchor()),
extension.extension_function().name());
}
}
- return build(context_, function_mapping);
+ return build(context_, function_mapping, partition_index_);
}
DB::ContextPtr ParserContext::queryContext() const
diff --git a/cpp-ch/local-engine/Parser/ParserContext.h
b/cpp-ch/local-engine/Parser/ParserContext.h
index c5c40199a2..2b591146cc 100644
--- a/cpp-ch/local-engine/Parser/ParserContext.h
+++ b/cpp-ch/local-engine/Parser/ParserContext.h
@@ -38,9 +38,10 @@ public:
ParserContext() = default;
using Ptr = std::shared_ptr<const ParserContext>;
- static Ptr build(DB::ContextPtr context_, const std::unordered_map<String,
String> & function_mapping_);
+ static Ptr
+ build(DB::ContextPtr context_, const std::unordered_map<String, String> &
function_mapping_, const size_t & partition_index_ = 0);
static Ptr build(DB::ContextPtr context_);
- static Ptr build(DB::ContextPtr context_, const substrait::Plan & plan_);
+ static Ptr build(DB::ContextPtr context_, const substrait::Plan & plan_,
const size_t & partition_index_ = 0);
DB::ContextPtr queryContext() const;
@@ -49,11 +50,13 @@ public:
std::optional<String> getFunctionNameInSignature(Int32 ref) const;
std::optional<String> getFunctionNameInSignature(const
substrait::Expression_ScalarFunction & func) const;
const std::unordered_map<String, String> & getLegacyFunctionMapping()
const;
+ size_t getPartitionIndex() const { return partition_index; }
private:
DB::ContextPtr query_context;
std::unordered_map<String, String> legacy_function_mapping;
std::unordered_map<Int32, FunctionSignature> function_mapping;
+ size_t partition_index = 0;
void addSelfDefinedFunctionMapping();
};
diff --git
a/cpp-ch/local-engine/Parser/scalar_function_parser/monotonicallyIncreasingId.cpp
b/cpp-ch/local-engine/Parser/scalar_function_parser/monotonicallyIncreasingId.cpp
new file mode 100644
index 0000000000..e9bdf60e4d
--- /dev/null
+++
b/cpp-ch/local-engine/Parser/scalar_function_parser/monotonicallyIncreasingId.cpp
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <DataTypes/DataTypesNumber.h>
+#include <Parser/FunctionParser.h>
+#include <Common/Exception.h>
+
+namespace local_engine
+{
+class SparkFunctionMonotonicallyIncreasingIDParser : public FunctionParser
+{
+public:
+ explicit SparkFunctionMonotonicallyIncreasingIDParser(ParserContextPtr
parser_context_) : FunctionParser(parser_context_) { }
+ ~SparkFunctionMonotonicallyIncreasingIDParser() override = default;
+ static constexpr auto name = "monotonically_increasing_id";
+ String getName() const { return name; }
+ String getCHFunctionName(const substrait::Expression_ScalarFunction &)
const override { return "sparkMonotonicallyIncreasingId"; }
+
+ const DB::ActionsDAG::Node *
+ parse(const substrait::Expression_ScalarFunction & substrait_func,
DB::ActionsDAG & actions_dag) const override
+ {
+ const DB::DataTypePtr type = std::make_shared<DB::DataTypeInt64>();
+ auto partition_index = parser_context->getPartitionIndex();
+
+ DB::ActionsDAG::NodeRawConstPtrs args;
+ args.reserve(1);
+ args.emplace_back(&actions_dag.addColumn(
+ DB::ColumnWithTypeAndName(type->createColumnConst(1,
partition_index), type, getUniqueName("partition_index"))));
+
+ auto ch_function_name = getCHFunctionName(substrait_func);
+ const auto * func_node = toFunctionNode(actions_dag, ch_function_name,
args);
+ return convertNodeTypeIfNeeded(substrait_func, func_node, actions_dag);
+ }
+};
+static FunctionParserRegister<SparkFunctionMonotonicallyIncreasingIDParser>
register_monotonically_increasing_id;
+}
diff --git a/cpp-ch/local-engine/local_engine_jni.cpp
b/cpp-ch/local-engine/local_engine_jni.cpp
index 6f3df78fb6..3d742e274d 100644
--- a/cpp-ch/local-engine/local_engine_jni.cpp
+++ b/cpp-ch/local-engine/local_engine_jni.cpp
@@ -229,7 +229,8 @@ JNIEXPORT jlong
Java_org_apache_gluten_vectorized_ExpressionEvaluatorJniWrapper_
jobjectArray split_infos,
jobjectArray iter_arr,
jbyteArray conf_plan,
- jboolean materialize_input)
+ jboolean materialize_input,
+ jint partition_index)
{
LOCAL_ENGINE_JNI_METHOD_START
auto query_context =
local_engine::QueryContext::instance().currentQueryContext();
@@ -243,7 +244,7 @@ JNIEXPORT jlong
Java_org_apache_gluten_vectorized_ExpressionEvaluatorJniWrapper_
const std::string::size_type plan_size = plan_a.length();
auto plan_pb =
local_engine::BinaryToMessage<substrait::Plan>({reinterpret_cast<const char
*>(plan_a.elems()), plan_size});
- auto parser_context = local_engine::ParserContext::build(query_context,
plan_pb);
+ auto parser_context = local_engine::ParserContext::build(query_context,
plan_pb, partition_index);
local_engine::SerializedPlanParser parser(parser_context);
jsize iter_num = env->GetArrayLength(iter_arr);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]