Skip to content

Commit 558f889

Browse files
committed
test: address read-optimized review comments
1 parent 9cd8e4a commit 558f889

3 files changed

Lines changed: 115 additions & 24 deletions

File tree

src/paimon/core/table/source/table_scan.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "paimon/common/predicate/predicate_validator.h"
2828
#include "paimon/common/types/data_field.h"
2929
#include "paimon/common/utils/fields_comparator.h"
30+
#include "paimon/common/utils/options_utils.h"
3031
#include "paimon/core/core_options.h"
3132
#include "paimon/core/index/index_file_handler.h"
3233
#include "paimon/core/manifest/index_manifest_file.h"
@@ -226,15 +227,12 @@ Result<std::unique_ptr<TableScan>> NewDataTableScan(const std::shared_ptr<ScanCo
226227
}
227228
table_schema = latest_table_schema.value();
228229
}
229-
const auto read_optimized_iter = context->GetOptions().find(kReadOptimizedScanOption);
230-
const bool read_optimized =
231-
read_optimized_iter != context->GetOptions().end() && read_optimized_iter->second == "true";
230+
PAIMON_ASSIGN_OR_RAISE(bool read_optimized,
231+
OptionsUtils::GetValueFromMap<bool>(context->GetOptions(),
232+
kReadOptimizedScanOption, false));
232233
// merge options
233234
auto options = table_schema->Options();
234235
for (const auto& [key, value] : context->GetOptions()) {
235-
if (key == kReadOptimizedScanOption) {
236-
continue;
237-
}
238236
options[key] = value;
239237
}
240238
PAIMON_ASSIGN_OR_RAISE(CoreOptions core_options,

src/paimon/core/table/system/read_optimized_system_table.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,9 @@ Result<std::unique_ptr<TableRead>> ReadOptimizedSystemTable::NewRead(
107107
.WithFileSystemSchemeToIdentifierMap(context->GetFileSystemSchemeToIdentifierMap())
108108
.SetPrefetchCacheMode(context->GetPrefetchCacheMode())
109109
.WithCacheConfig(context->GetCacheConfig())
110-
.WithCache(context->GetCache());
111-
if (!context->GetReadFieldIds().empty()) {
112-
builder.SetReadFieldIds(context->GetReadFieldIds());
113-
} else {
114-
builder.SetReadFieldNames(context->GetReadFieldNames());
115-
}
110+
.WithCache(context->GetCache())
111+
.SetReadFieldNames(context->GetReadFieldNames())
112+
.SetReadFieldIds(context->GetReadFieldIds());
116113
if (context->GetSpecificTableSchema().has_value()) {
117114
builder.SetTableSchema(context->GetSpecificTableSchema().value());
118115
}

test/inte/read_inte_test.cpp

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,15 @@ std::vector<std::string> StructFieldNames(const std::shared_ptr<arrow::StructArr
268268
return arrow::schema(array->type()->fields())->field_names();
269269
}
270270

271-
Result<SystemTableReadResult> ReadSystemTable(const std::string& system_table_path,
272-
const std::map<std::string, std::string>& options,
273-
bool streaming_mode = false) {
271+
Result<SystemTableReadResult> ReadSystemTable(
272+
const std::string& system_table_path, const std::map<std::string, std::string>& options,
273+
bool streaming_mode = false, const std::shared_ptr<Predicate>& predicate = nullptr,
274+
const std::vector<std::string>& read_field_names = {}) {
274275
ScanContextBuilder scan_context_builder(system_table_path);
275276
scan_context_builder.SetOptions(options).WithStreamingMode(streaming_mode);
277+
if (predicate) {
278+
scan_context_builder.SetPredicate(predicate);
279+
}
276280
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<ScanContext> scan_context,
277281
scan_context_builder.Finish());
278282
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<TableScan> table_scan,
@@ -281,6 +285,12 @@ Result<SystemTableReadResult> ReadSystemTable(const std::string& system_table_pa
281285

282286
ReadContextBuilder read_context_builder(system_table_path);
283287
read_context_builder.SetOptions(options);
288+
if (predicate) {
289+
read_context_builder.SetPredicate(predicate);
290+
}
291+
if (!read_field_names.empty()) {
292+
read_context_builder.SetReadFieldNames(read_field_names);
293+
}
284294
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<ReadContext> read_context,
285295
read_context_builder.Finish());
286296
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<TableRead> table_read,
@@ -292,8 +302,8 @@ Result<SystemTableReadResult> ReadSystemTable(const std::string& system_table_pa
292302
return SystemTableReadResult(std::move(batch_reader), result);
293303
}
294304

295-
Status WriteAndFullCompact(TestHelper* helper, std::unique_ptr<RecordBatch>&& batch,
296-
int64_t commit_identifier) {
305+
Status WriteAndFullCompact(std::unique_ptr<RecordBatch>&& batch, int64_t commit_identifier,
306+
TestHelper* helper) {
297307
PAIMON_RETURN_NOT_OK(helper->write_->Write(std::move(batch)));
298308
PAIMON_RETURN_NOT_OK(
299309
helper->write_->Compact(/*partition=*/{}, /*bucket=*/0, /*full_compaction=*/true));
@@ -312,6 +322,18 @@ void AssertStructArrayEqualsJson(const std::shared_ptr<arrow::StructArray>& actu
312322
<< "expected: " << expected->ToString() << "\nactual: " << actual->ToString();
313323
}
314324

325+
Result<int64_t> CountDataFiles(const std::vector<std::shared_ptr<Split>>& splits) {
326+
int64_t file_count = 0;
327+
for (const auto& split : splits) {
328+
auto data_split = std::dynamic_pointer_cast<DataSplit>(split);
329+
if (!data_split) {
330+
return Status::Invalid("expected data split");
331+
}
332+
file_count += data_split->GetFileList().size();
333+
}
334+
return file_count;
335+
}
336+
315337
} // namespace
316338

317339
std::vector<TestParam> PrepareTestParam() {
@@ -819,7 +841,7 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTable) {
819841
ASSERT_OK_AND_ASSIGN(std::unique_ptr<RecordBatch> batch_1,
820842
TestHelper::MakeRecordBatch(row_type, R"([[1, 10], [2, 20]])",
821843
/*partition_map=*/{}, /*bucket=*/0, {}));
822-
ASSERT_OK(WriteAndFullCompact(helper.get(), std::move(batch_1), /*commit_identifier=*/0));
844+
ASSERT_OK(WriteAndFullCompact(std::move(batch_1), /*commit_identifier=*/0, helper.get()));
823845

824846
ASSERT_OK_AND_ASSIGN(SystemTableReadResult compacted_result,
825847
ReadSystemTable(table_path + "$ro", options));
@@ -845,7 +867,7 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTable) {
845867
ASSERT_OK_AND_ASSIGN(std::unique_ptr<RecordBatch> batch_3,
846868
TestHelper::MakeRecordBatch(row_type, R"([[2, 21], [3, 31]])",
847869
/*partition_map=*/{}, /*bucket=*/0, {}));
848-
ASSERT_OK(WriteAndFullCompact(helper.get(), std::move(batch_3), /*commit_identifier=*/2));
870+
ASSERT_OK(WriteAndFullCompact(std::move(batch_3), /*commit_identifier=*/2, helper.get()));
849871
ASSERT_OK_AND_ASSIGN(SystemTableReadResult refreshed_result,
850872
ReadSystemTable(table_path + "$ro", options));
851873
std::shared_ptr<arrow::ChunkedArray> expected_refreshed;
@@ -895,6 +917,74 @@ TEST(SystemTableReadInteTest, TestReadOptimizedAppendOnlySystemTableWithStreamin
895917
ASSERT_TRUE(result.array->Equals(expected)) << result.array->ToString();
896918
}
897919

920+
TEST(SystemTableReadInteTest, TestReadOptimizedPrimaryKeyProjectionAndPredicatePushdown) {
921+
arrow::FieldVector fields = {
922+
arrow::field("k", arrow::int32()),
923+
arrow::field("v", arrow::int32()),
924+
arrow::field("extra", arrow::int32()),
925+
};
926+
auto schema = arrow::schema(fields);
927+
std::map<std::string, std::string> options = {
928+
{Options::FILE_SYSTEM, "local"},
929+
{Options::FILE_FORMAT, "parquet"},
930+
{Options::MANIFEST_FORMAT, "avro"},
931+
{Options::BUCKET, "1"},
932+
{Options::BUCKET_KEY, "k"},
933+
{Options::WRITE_BATCH_SIZE, "1"},
934+
{"parquet.page.size", "1"},
935+
{"parquet.enable-dictionary", "false"},
936+
{"parquet.write.enable-page-index", "true"},
937+
{"parquet.write.max-row-group-length", "1"},
938+
{"parquet.read.enable-page-index-filter", "true"}};
939+
auto dir = UniqueTestDirectory::Create();
940+
ASSERT_TRUE(dir);
941+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<TestHelper> helper,
942+
TestHelper::Create(dir->Str(), schema,
943+
/*partition_keys=*/{}, /*primary_keys=*/{"k"}, options,
944+
/*is_streaming_mode=*/true));
945+
std::string table_path = PathUtil::JoinPath(dir->Str(), "foo.db/bar");
946+
auto row_type = arrow::struct_(fields);
947+
948+
ASSERT_OK_AND_ASSIGN(
949+
std::unique_ptr<RecordBatch> batch_1,
950+
TestHelper::MakeRecordBatch(row_type, R"([[1, 10, 100], [2, 20, 200], [3, 30, 300]])",
951+
/*partition_map=*/{}, /*bucket=*/0, {}));
952+
ASSERT_OK(WriteAndFullCompact(std::move(batch_1), /*commit_identifier=*/0, helper.get()));
953+
954+
std::shared_ptr<Predicate> predicate =
955+
PredicateBuilder::Equal(/*field_index=*/0, /*field_name=*/"k", FieldType::INT, Literal(2));
956+
957+
ScanContextBuilder ro_scan_context_builder(table_path + "$ro");
958+
ro_scan_context_builder.SetOptions(options).SetPredicate(predicate);
959+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<ScanContext> ro_scan_context,
960+
ro_scan_context_builder.Finish());
961+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<TableScan> ro_table_scan,
962+
TableScan::Create(std::move(ro_scan_context)));
963+
ASSERT_OK_AND_ASSIGN(std::shared_ptr<Plan> ro_plan, ro_table_scan->CreatePlan());
964+
ASSERT_OK_AND_ASSIGN(int64_t ro_file_count, CountDataFiles(ro_plan->Splits()));
965+
ASSERT_EQ(ro_file_count, 1);
966+
967+
ReadContextBuilder read_context_builder(table_path + "$ro");
968+
// Do not enable row-level predicate filtering: the result must come from the file reader's
969+
// row-group/page predicate pushdown.
970+
read_context_builder.SetOptions(options).SetPredicate(predicate).SetReadFieldNames({"k", "v"});
971+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<ReadContext> read_context, read_context_builder.Finish());
972+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<TableRead> table_read,
973+
TableRead::Create(std::move(read_context)));
974+
ASSERT_OK_AND_ASSIGN(std::unique_ptr<BatchReader> batch_reader,
975+
table_read->CreateReader(ro_plan->Splits()));
976+
ASSERT_OK_AND_ASSIGN(std::shared_ptr<arrow::ChunkedArray> result,
977+
ReadResultCollector::CollectResult(batch_reader.get()));
978+
std::shared_ptr<arrow::DataType> expected_type =
979+
arrow::struct_({arrow::field("_VALUE_KIND", arrow::int8()),
980+
arrow::field("k", arrow::int32()), arrow::field("v", arrow::int32())});
981+
std::shared_ptr<arrow::ChunkedArray> expected;
982+
ASSERT_TRUE(arrow::ipc::internal::json::ChunkedArrayFromJSON(expected_type, {R"([[0, 2, 20]])"},
983+
&expected)
984+
.ok());
985+
ASSERT_TRUE(result->Equals(expected)) << result->ToString();
986+
}
987+
898988
TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithBranch) {
899989
arrow::FieldVector fields = {
900990
arrow::field("k", arrow::int32()),
@@ -919,8 +1009,7 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithBranch) {
9191009
ASSERT_OK_AND_ASSIGN(std::unique_ptr<RecordBatch> branch_batch,
9201010
TestHelper::MakeRecordBatch(row_type, R"([[1, 10], [2, 20]])",
9211011
/*partition_map=*/{}, /*bucket=*/0, {}));
922-
ASSERT_OK(WriteAndFullCompact(helper.get(), std::move(branch_batch),
923-
/*commit_identifier=*/0));
1012+
ASSERT_OK(WriteAndFullCompact(std::move(branch_batch), /*commit_identifier=*/0, helper.get()));
9241013

9251014
std::string branch_path = PathUtil::JoinPath(table_path, "branch/branch-rt");
9261015
std::filesystem::create_directories(branch_path);
@@ -932,8 +1021,7 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithBranch) {
9321021
ASSERT_OK_AND_ASSIGN(std::unique_ptr<RecordBatch> main_batch,
9331022
TestHelper::MakeRecordBatch(row_type, R"([[1, 11], [3, 30]])",
9341023
/*partition_map=*/{}, /*bucket=*/0, {}));
935-
ASSERT_OK(WriteAndFullCompact(helper.get(), std::move(main_batch),
936-
/*commit_identifier=*/1));
1024+
ASSERT_OK(WriteAndFullCompact(std::move(main_batch), /*commit_identifier=*/1, helper.get()));
9371025

9381026
ASSERT_OK_AND_ASSIGN(SystemTableReadResult result,
9391027
ReadSystemTable(table_path + "$branch_rt$ro", options));
@@ -945,6 +1033,14 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithBranch) {
9451033
expected_type, {R"([[0, 1, 10], [0, 2, 20]])"}, &expected)
9461034
.ok());
9471035
ASSERT_TRUE(result.array->Equals(expected)) << result.array->ToString();
1036+
1037+
ASSERT_OK_AND_ASSIGN(SystemTableReadResult main_result,
1038+
ReadSystemTable(table_path + "$ro", options));
1039+
std::shared_ptr<arrow::ChunkedArray> expected_main;
1040+
ASSERT_TRUE(arrow::ipc::internal::json::ChunkedArrayFromJSON(
1041+
expected_type, {R"([[0, 1, 11], [0, 2, 20], [0, 3, 30]])"}, &expected_main)
1042+
.ok());
1043+
ASSERT_TRUE(main_result.array->Equals(expected_main)) << main_result.array->ToString();
9481044
}
9491045

9501046
TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithFirstRowMergeEngine) {
@@ -973,7 +1069,7 @@ TEST(SystemTableReadInteTest, TestReadOptimizedSystemTableWithFirstRowMergeEngin
9731069
std::unique_ptr<RecordBatch> batch,
9741070
TestHelper::MakeRecordBatch(arrow::struct_(fields), R"([[1, 10], [2, 20]])",
9751071
/*partition_map=*/{}, /*bucket=*/0, {}));
976-
ASSERT_OK(WriteAndFullCompact(helper.get(), std::move(batch), /*commit_identifier=*/0));
1072+
ASSERT_OK(WriteAndFullCompact(std::move(batch), /*commit_identifier=*/0, helper.get()));
9771073

9781074
ASSERT_OK_AND_ASSIGN(SystemTableReadResult result,
9791075
ReadSystemTable(table_path + "$ro", options));

0 commit comments

Comments
 (0)