Skip to content

Commit 31f0033

Browse files
authored
feat(format): optimize avro read performance and support reading various nested types (alibaba#76)
1 parent 5eaa3d9 commit 31f0033

91 files changed

Lines changed: 1743 additions & 1098 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

LICENSE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,9 @@ This product includes code from Apache Iceberg C++.
263263
* .devcontainer/devcontainer.json.template
264264
* CI utilities:
265265
* .pre-commit-config.yaml
266+
* Avro direct decoder/encoder:
267+
* src/paimon/format/avro/avro_direct_decoder.cpp
268+
* src/paimon/format/avro/avro_direct_decoder.h
266269

267270
Copyright: 2024-2025 The Apache Software Foundation.
268271
Home page: https://iceberg.apache.org/

src/paimon/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ if(PAIMON_BUILD_TESTS)
386386
common/types/data_type_json_parser_test.cpp
387387
common/types/row_kind_test.cpp
388388
common/types/data_type_test.cpp
389+
common/utils/arrow/arrow_utils_test.cpp
389390
common/utils/arrow/mem_utils_test.cpp
390391
common/utils/arrow/status_utils_test.cpp
391392
common/utils/concurrent_hash_map_test.cpp

src/paimon/common/utils/arrow/arrow_utils.h

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,41 @@
1616

1717
#pragma once
1818

19-
#include "arrow/c/helpers.h"
19+
#include <vector>
20+
21+
#include "arrow/api.h"
22+
#include "fmt/format.h"
23+
#include "paimon/result.h"
2024

2125
namespace paimon {
22-
inline void ArrowArrayInit(struct ArrowArray* array) {
23-
ArrowArrayMarkReleased(array);
24-
}
2526

26-
inline void ArrowSchemaInit(struct ArrowSchema* schema) {
27-
ArrowSchemaMarkReleased(schema);
28-
}
27+
class ArrowUtils {
28+
public:
29+
ArrowUtils() = delete;
30+
~ArrowUtils() = delete;
31+
32+
static Result<std::shared_ptr<arrow::Schema>> DataTypeToSchema(
33+
const std::shared_ptr<::arrow::DataType>& data_type) {
34+
if (data_type->id() != arrow::Type::STRUCT) {
35+
return Status::Invalid(fmt::format("Expected struct data type, actual data type: {}",
36+
data_type->ToString()));
37+
}
38+
const auto& struct_type = std::static_pointer_cast<arrow::StructType>(data_type);
39+
return std::make_shared<arrow::Schema>(struct_type->fields());
40+
}
41+
42+
static std::vector<int32_t> CreateProjection(
43+
const std::shared_ptr<::arrow::Schema>& file_schema,
44+
const arrow::FieldVector& read_fields) {
45+
std::vector<int32_t> target_to_src_mapping;
46+
target_to_src_mapping.reserve(read_fields.size());
47+
for (const auto& field : read_fields) {
48+
auto src_field_idx = file_schema->GetFieldIndex(field->name());
49+
assert(src_field_idx >= 0);
50+
target_to_src_mapping.push_back(src_field_idx);
51+
}
52+
return target_to_src_mapping;
53+
}
54+
};
55+
2956
} // namespace paimon
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
#include "paimon/common/utils/arrow/arrow_utils.h"
18+
19+
#include "arrow/api.h"
20+
#include "gtest/gtest.h"
21+
#include "paimon/common/types/data_field.h"
22+
23+
namespace paimon::test {
24+
25+
TEST(ArrowUtilsTest, TestCreateProjection) {
26+
std::vector<DataField> read_fields = {DataField(1, arrow::field("k1", arrow::int32())),
27+
DataField(3, arrow::field("p1", arrow::int32())),
28+
DataField(5, arrow::field("s1", arrow::utf8())),
29+
DataField(6, arrow::field("v0", arrow::float64())),
30+
DataField(7, arrow::field("v1", arrow::boolean()))};
31+
auto read_schema = DataField::ConvertDataFieldsToArrowSchema(read_fields);
32+
33+
std::vector<DataField> file_fields = {DataField(0, arrow::field("k0", arrow::int32())),
34+
DataField(1, arrow::field("k1", arrow::int32())),
35+
DataField(3, arrow::field("p1", arrow::int32())),
36+
DataField(5, arrow::field("s1", arrow::utf8())),
37+
DataField(6, arrow::field("v0", arrow::float64())),
38+
DataField(7, arrow::field("v1", arrow::boolean())),
39+
DataField(4, arrow::field("s0", arrow::utf8()))};
40+
auto file_schema = DataField::ConvertDataFieldsToArrowSchema(file_fields);
41+
42+
auto projection = ArrowUtils::CreateProjection(file_schema, read_schema->fields());
43+
std::vector<int32_t> expected_projection = {1, 2, 3, 4, 5};
44+
ASSERT_EQ(projection, expected_projection);
45+
}
46+
47+
} // namespace paimon::test

src/paimon/common/utils/status.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ void Status::AddContextLine(const char* filename, int line, const char* function
142142
const char* expr) {
143143
assert(!ok() && "Cannot add context line to ok status");
144144
std::stringstream ss;
145-
ss << "\nIn " << filename << ", line " << line << ", function: " << function_name
145+
ss << "\nIn " << filename << ":" << line << ", function: " << function_name
146146
<< ", code: " << expr;
147147
state_->msg += ss.str();
148148
}

src/paimon/core/io/row_to_arrow_array_converter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Status RowToArrowArrayConverter<T, R>::Reserve(arrow::ArrayBuilder* array_builde
167167
PAIMON_ASSIGN_OR_RAISE(auto* struct_builder,
168168
CastToTypedBuilder<arrow::StructBuilder>(array_builder));
169169
for (int32_t i = 0; i < struct_builder->num_fields(); i++) {
170-
// reserve item builder in map
170+
// reserve item builder in struct
171171
PAIMON_RETURN_NOT_OK(Reserve(struct_builder->field_builder(i), idx));
172172
}
173173
break;

src/paimon/core/io/single_file_writer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ Status SingleFileWriter<T, R>::Write(T record) {
175175
}
176176
} else {
177177
ArrowArray array;
178-
ArrowArrayInit(&array);
178+
ArrowArrayMarkReleased(&array); // reset array
179179
ScopeGuard inner_guard([&array]() { ArrowArrayRelease(&array); });
180180
PAIMON_RETURN_NOT_OK(converter_(std::move(record), &array));
181181
record_count = array.length;

src/paimon/core/operation/abstract_split_read.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ Result<std::unique_ptr<FileBatchReader>> AbstractSplitRead::CreateFileBatchReade
147147
// lance do not support stream build with input stream
148148
return reader_builder->Build(data_file_path);
149149
}
150-
if (context_->EnablePrefetch() && file_format_identifier != "blob") {
150+
// TODO(zhanyu.fyh): orc format support prefetch
151+
if (context_->EnablePrefetch() && file_format_identifier != "blob" &&
152+
file_format_identifier != "avro") {
151153
PAIMON_ASSIGN_OR_RAISE(
152154
std::unique_ptr<PrefetchFileBatchReaderImpl> prefetch_reader,
153155
PrefetchFileBatchReaderImpl::Create(

src/paimon/core/operation/merge_file_split_read.cpp

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "paimon/common/reader/concat_batch_reader.h"
3333
#include "paimon/common/table/special_fields.h"
3434
#include "paimon/common/types/data_field.h"
35+
#include "paimon/common/utils/arrow/arrow_utils.h"
3536
#include "paimon/common/utils/arrow/status_utils.h"
3637
#include "paimon/core/core_options.h"
3738
#include "paimon/core/deletionvectors/apply_deletion_vector_batch_reader.h"
@@ -105,7 +106,8 @@ Result<std::unique_ptr<MergeFileSplitRead>> MergeFileSplitRead::Create(
105106
int32_t key_arity = trimmed_primary_key.size();
106107

107108
// projection is the mapping from value_schema in KeyValue object to raw_read_schema
108-
std::vector<int32_t> projection = CreateProjection(context->GetReadSchema(), value_schema);
109+
std::vector<int32_t> projection =
110+
ArrowUtils::CreateProjection(value_schema, context->GetReadSchema()->fields());
109111

110112
return std::unique_ptr<MergeFileSplitRead>(new MergeFileSplitRead(
111113
path_factory, context,
@@ -368,19 +370,6 @@ Result<std::shared_ptr<Predicate>> MergeFileSplitRead::GenerateKeyPredicates(
368370
return PredicateUtils::ExcludePredicateWithFields(predicate, non_primary_keys);
369371
}
370372

371-
std::vector<int32_t> MergeFileSplitRead::CreateProjection(
372-
const std::shared_ptr<arrow::Schema>& raw_read_schema,
373-
const std::shared_ptr<arrow::Schema>& value_schema) {
374-
std::vector<int32_t> target_to_src_mapping;
375-
target_to_src_mapping.reserve(raw_read_schema->num_fields());
376-
for (const auto& field : raw_read_schema->fields()) {
377-
auto src_field_idx = value_schema->GetFieldIndex(field->name());
378-
assert(src_field_idx >= 0);
379-
target_to_src_mapping.push_back(src_field_idx);
380-
}
381-
return target_to_src_mapping;
382-
}
383-
384373
Result<std::unique_ptr<BatchReader>> MergeFileSplitRead::CreateReaderForSection(
385374
const std::vector<SortedRun>& section, const std::string& bucket_path,
386375
const BinaryRow& partition,

src/paimon/core/operation/merge_file_split_read.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,6 @@ class MergeFileSplitRead : public AbstractSplitRead {
154154
static Result<std::shared_ptr<Predicate>> GenerateKeyPredicates(
155155
const std::shared_ptr<Predicate>& predicate, const TableSchema& table_schema);
156156

157-
static std::vector<int32_t> CreateProjection(
158-
const std::shared_ptr<arrow::Schema>& raw_read_schema,
159-
const std::shared_ptr<arrow::Schema>& value_schema);
160-
161157
private:
162158
int32_t key_arity_;
163159
// schema of value member in KeyValue object

0 commit comments

Comments
 (0)