Skip to content

Commit 37b35c7

Browse files
feat(core): Add bucket function implementation (alibaba#218)
1 parent 948324c commit 37b35c7

20 files changed

Lines changed: 1608 additions & 19 deletions

include/paimon/defs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ struct PAIMON_EXPORT Options {
414414
/// "lookup.cache.high-priority-pool-ratio" - The fraction of cache memory that is reserved for
415415
/// high-priority data like index, filter. Default value is 0.25.
416416
static const char LOOKUP_CACHE_HIGH_PRIO_POOL_RATIO[];
417+
/// "bucket-function.type" - The bucket function type for paimon bucket.
418+
/// Values can be: "default", "mod", "hive". Default value is "default".
419+
static const char BUCKET_FUNCTION_TYPE[];
417420
/// "lookup.cache-file-retention" - The cached files retention time for lookup.
418421
/// After the file expires, if there is a need for access, it will be re-read from the DFS
419422
/// to build an index on the local disk. Default value is 1 hour.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2026-present Alibaba Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <cstdint>
20+
21+
#include "paimon/defs.h"
22+
#include "paimon/visibility.h"
23+
24+
namespace paimon {
25+
26+
/// Specifies the bucket function type for paimon bucket.
27+
/// This determines how rows are assigned to buckets during data writing.
28+
enum class BucketFunctionType {
29+
/// The default bucket function which will use arithmetic:
30+
/// bucket_id = abs(hash_bucket_binary_row % numBuckets) to get bucket.
31+
DEFAULT = 1,
32+
/// The modulus bucket function which will use modulus arithmetic:
33+
/// bucket_id = floorMod(bucket_key_value, numBuckets) to get bucket.
34+
/// Note: the bucket key must be a single field of INT or BIGINT datatype.
35+
MOD = 2,
36+
/// The hive bucket function which will use hive-compatible hash arithmetic to get bucket.
37+
HIVE = 3
38+
};
39+
40+
/// Describes a field's type information needed for Hive hashing.
41+
struct PAIMON_EXPORT HiveFieldInfo {
42+
FieldType type;
43+
int32_t precision = 0; // Used for DECIMAL type
44+
int32_t scale = 0; // Used for DECIMAL type
45+
46+
explicit HiveFieldInfo(FieldType t) : type(t) {}
47+
HiveFieldInfo(FieldType t, int32_t p, int32_t s) : type(t), precision(p), scale(s) {}
48+
};
49+
50+
} // namespace paimon

include/paimon/utils/bucket_id_calculator.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@
1717
#pragma once
1818
#include <cstdint>
1919
#include <memory>
20+
#include <vector>
2021

2122
#include "paimon/memory/memory_pool.h"
2223
#include "paimon/result.h"
2324
#include "paimon/status.h"
25+
#include "paimon/utils/bucket_function_type.h"
2426
#include "paimon/visibility.h"
2527

2628
struct ArrowSchema;
2729
struct ArrowArray;
2830

2931
namespace paimon {
32+
class BucketFunction;
3033
class MemoryPool;
3134

3235
/// Calculator for determining bucket ids based on the given bucket keys.
@@ -35,18 +38,40 @@ class MemoryPool;
3538
/// hash-based distribution to ensure even data distribution across buckets.
3639
class PAIMON_EXPORT BucketIdCalculator {
3740
public:
38-
/// Create `BucketIdCalculator` with custom memory pool.
41+
/// Create `BucketIdCalculator` with default bucket function.
3942
/// @param is_pk_table Whether this is for a primary key table.
4043
/// @param num_buckets Number of buckets.
4144
/// @param pool Memory pool for memory allocation.
4245
static Result<std::unique_ptr<BucketIdCalculator>> Create(
4346
bool is_pk_table, int32_t num_buckets, const std::shared_ptr<MemoryPool>& pool);
4447

45-
/// Create `BucketIdCalculator` with default memory pool.
48+
/// Create `BucketIdCalculator` with a custom bucket function.
4649
/// @param is_pk_table Whether this is for a primary key table.
4750
/// @param num_buckets Number of buckets.
48-
static Result<std::unique_ptr<BucketIdCalculator>> Create(bool is_pk_table,
49-
int32_t num_buckets);
51+
/// @param bucket_function The bucket function to use for bucket assignment.
52+
/// @param pool Memory pool for memory allocation.
53+
static Result<std::unique_ptr<BucketIdCalculator>> Create(
54+
bool is_pk_table, int32_t num_buckets, std::unique_ptr<BucketFunction> bucket_function,
55+
const std::shared_ptr<MemoryPool>& pool);
56+
57+
/// Create `BucketIdCalculator` with MOD bucket function.
58+
/// @param is_pk_table Whether this is for a primary key table.
59+
/// @param num_buckets Number of buckets.
60+
/// @param bucket_key_type The type of the single bucket key field. Must be INT or BIGINT.
61+
/// @param pool Memory pool for memory allocation.
62+
static Result<std::unique_ptr<BucketIdCalculator>> CreateMod(
63+
bool is_pk_table, int32_t num_buckets, FieldType bucket_key_type,
64+
const std::shared_ptr<MemoryPool>& pool);
65+
66+
/// Create `BucketIdCalculator` with HIVE bucket function.
67+
/// @param is_pk_table Whether this is for a primary key table.
68+
/// @param num_buckets Number of buckets.
69+
/// @param field_infos The detailed type info of all fields in the bucket key row.
70+
/// @param pool Memory pool for memory allocation.
71+
static Result<std::unique_ptr<BucketIdCalculator>> CreateHive(
72+
bool is_pk_table, int32_t num_buckets, const std::vector<HiveFieldInfo>& field_infos,
73+
const std::shared_ptr<MemoryPool>& pool);
74+
5075
/// Calculate bucket ids for the given bucket keys.
5176
/// @param bucket_keys Arrow struct array containing the bucket key values.
5277
/// @param bucket_schema Arrow schema describing the structure of bucket_keys.
@@ -57,12 +82,16 @@ class PAIMON_EXPORT BucketIdCalculator {
5782
Status CalculateBucketIds(ArrowArray* bucket_keys, ArrowSchema* bucket_schema,
5883
int32_t* bucket_ids) const;
5984

85+
/// Destructor
86+
~BucketIdCalculator();
87+
6088
private:
61-
BucketIdCalculator(int32_t num_buckets, const std::shared_ptr<MemoryPool>& pool)
62-
: num_buckets_(num_buckets), pool_(pool) {}
89+
BucketIdCalculator(int32_t num_buckets, std::unique_ptr<BucketFunction> bucket_function,
90+
const std::shared_ptr<MemoryPool>& pool);
6391

6492
private:
6593
int32_t num_buckets_;
94+
std::unique_ptr<BucketFunction> bucket_function_;
6695
std::shared_ptr<MemoryPool> pool_;
6796
};
6897
} // namespace paimon

src/paimon/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ set(PAIMON_CORE_SRCS
149149
core/disk/io_manager.cpp
150150
core/append/append_only_writer.cpp
151151
core/append/bucketed_append_compact_manager.cpp
152+
core/bucket/hive_bucket_function.cpp
153+
core/bucket/mod_bucket_function.cpp
152154
core/casting/binary_to_string_cast_executor.cpp
153155
core/casting/boolean_to_decimal_cast_executor.cpp
154156
core/casting/boolean_to_numeric_cast_executor.cpp
@@ -514,6 +516,9 @@ if(PAIMON_BUILD_TESTS)
514516
SOURCES
515517
core/append/append_only_writer_test.cpp
516518
core/append/bucketed_append_compact_manager_test.cpp
519+
core/bucket/default_bucket_function_test.cpp
520+
core/bucket/hive_bucket_function_test.cpp
521+
core/bucket/mod_bucket_function_test.cpp
517522
core/casting/cast_executor_factory_test.cpp
518523
core/casting/cast_executor_test.cpp
519524
core/casting/casted_row_test.cpp

src/paimon/common/defs.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ const char Options::LOOKUP_COMPACT[] = "lookup-compact";
117117
const char Options::LOOKUP_COMPACT_MAX_INTERVAL[] = "lookup-compact.max-interval";
118118
const char Options::LOOKUP_CACHE_MAX_MEMORY_SIZE[] = "lookup.cache-max-memory-size";
119119
const char Options::LOOKUP_CACHE_HIGH_PRIO_POOL_RATIO[] = "lookup.cache.high-priority-pool-ratio";
120+
const char Options::BUCKET_FUNCTION_TYPE[] = "bucket-function.type";
120121
const char Options::LOOKUP_CACHE_FILE_RETENTION[] = "lookup.cache-file-retention";
121122
const char Options::LOOKUP_CACHE_MAX_DISK_SIZE[] = "lookup.cache-max-disk-size";
122123

src/paimon/common/utils/bucket_id_calculator.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
#include "paimon/common/utils/arrow/status_utils.h"
4545
#include "paimon/common/utils/date_time_utils.h"
4646
#include "paimon/common/utils/scope_guard.h"
47+
#include "paimon/core/bucket/bucket_function.h"
48+
#include "paimon/core/bucket/default_bucket_function.h"
49+
#include "paimon/core/bucket/hive_bucket_function.h"
50+
#include "paimon/core/bucket/mod_bucket_function.h"
4751
#include "paimon/data/decimal.h"
4852
#include "paimon/data/timestamp.h"
4953
#include "paimon/memory/memory_pool.h"
@@ -236,8 +240,21 @@ static Result<WriteFunction> WriteBucketRow(int32_t col_id,
236240
}
237241
} // namespace
238242

243+
BucketIdCalculator::BucketIdCalculator(int32_t num_buckets,
244+
std::unique_ptr<BucketFunction> bucket_function,
245+
const std::shared_ptr<MemoryPool>& pool)
246+
: num_buckets_(num_buckets), bucket_function_(std::move(bucket_function)), pool_(pool) {}
247+
248+
BucketIdCalculator::~BucketIdCalculator() = default;
249+
239250
Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::Create(
240251
bool is_pk_table, int32_t num_buckets, const std::shared_ptr<MemoryPool>& pool) {
252+
return Create(is_pk_table, num_buckets, std::make_unique<DefaultBucketFunction>(), pool);
253+
}
254+
255+
Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::Create(
256+
bool is_pk_table, int32_t num_buckets, std::unique_ptr<BucketFunction> bucket_function,
257+
const std::shared_ptr<MemoryPool>& pool) {
241258
if (num_buckets == 0 || num_buckets < -2) {
242259
return Status::Invalid("num buckets must be -1 or -2 or greater than 0");
243260
}
@@ -249,12 +266,22 @@ Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::Create(
249266
if (!is_pk_table && num_buckets == -2) {
250267
return Status::Invalid("Append table not support PostponeBucketMode");
251268
}
252-
return std::unique_ptr<BucketIdCalculator>(new BucketIdCalculator(num_buckets, pool));
269+
return std::unique_ptr<BucketIdCalculator>(
270+
new BucketIdCalculator(num_buckets, std::move(bucket_function), pool));
271+
}
272+
273+
Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::CreateMod(
274+
bool is_pk_table, int32_t num_buckets, FieldType bucket_key_type,
275+
const std::shared_ptr<MemoryPool>& pool) {
276+
PAIMON_ASSIGN_OR_RAISE(auto mod_func, ModBucketFunction::Create(bucket_key_type));
277+
return Create(is_pk_table, num_buckets, std::move(mod_func), pool);
253278
}
254279

255-
Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::Create(bool is_pk_table,
256-
int32_t num_buckets) {
257-
return Create(is_pk_table, num_buckets, GetDefaultPool());
280+
Result<std::unique_ptr<BucketIdCalculator>> BucketIdCalculator::CreateHive(
281+
bool is_pk_table, int32_t num_buckets, const std::vector<HiveFieldInfo>& field_infos,
282+
const std::shared_ptr<MemoryPool>& pool) {
283+
PAIMON_ASSIGN_OR_RAISE(auto hive_func, HiveBucketFunction::Create(field_infos));
284+
return Create(is_pk_table, num_buckets, std::move(hive_func), pool);
258285
}
259286

260287
Status BucketIdCalculator::CalculateBucketIds(ArrowArray* bucket_keys, ArrowSchema* bucket_schema,
@@ -298,7 +325,7 @@ Status BucketIdCalculator::CalculateBucketIds(ArrowArray* bucket_keys, ArrowSche
298325
write_functions[col](row, &row_writer);
299326
}
300327
row_writer.Complete();
301-
bucket_ids[row] = std::abs(bucket_row.HashCode() % num_buckets_);
328+
bucket_ids[row] = bucket_function_->Bucket(bucket_row, num_buckets_);
302329
}
303330
guard.Release();
304331
return Status::OK();

0 commit comments

Comments
 (0)