From 1b0ae413704c87b1065b846d3e8b0b08e7792c78 Mon Sep 17 00:00:00 2001 From: "lisizhuo.lsz" Date: Wed, 26 Aug 2026 19:09:48 +0800 Subject: [PATCH] fix(compaction): persist keys in lookup SST files while first-row merge function --- ...ookup_merge_tree_compact_rewriter_test.cpp | 39 +++++++++++++++++++ src/paimon/core/mergetree/lookup_levels.cpp | 14 +------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/paimon/core/mergetree/compact/lookup_merge_tree_compact_rewriter_test.cpp b/src/paimon/core/mergetree/compact/lookup_merge_tree_compact_rewriter_test.cpp index bbc1608c4..eeb7e0ce2 100644 --- a/src/paimon/core/mergetree/compact/lookup_merge_tree_compact_rewriter_test.cpp +++ b/src/paimon/core/mergetree/compact/lookup_merge_tree_compact_rewriter_test.cpp @@ -484,6 +484,45 @@ TEST_F(LookupMergeTreeCompactRewriterTest, TestFirstRowRewrite) { CheckResult(compact_file_name, table_schema, "orc", expected_array); } +TEST_F(LookupMergeTreeCompactRewriterTest, TestFirstRowLooksUpExistingKeys) { + std::map options = {{Options::MERGE_ENGINE, "first-row"}, + {Options::FILE_FORMAT, "orc"}}; + ASSERT_OK_AND_ASSIGN(CoreOptions core_options, CoreOptions::FromMap(options)); + ASSERT_OK_AND_ASSIGN(auto table_path, CreateTable(options)); + auto schema_manager = std::make_shared(fs_, table_path); + ASSERT_OK_AND_ASSIGN(auto table_schema, schema_manager->ReadSchema(0)); + + ASSERT_OK_AND_ASSIGN(auto level0_file, + NewFiles(/*level=*/0, /*last_sequence_number=*/0, table_path, core_options, + "[[1, 111], [2, 22]]")); + ASSERT_OK_AND_ASSIGN(auto high_level_file, NewFiles(/*level=*/2, /*last_sequence_number=*/-1, + table_path, core_options, "[[1, 11]]")); + auto processor_factory = std::make_shared(); + ASSERT_OK_AND_ASSIGN(auto lookup_levels, + CreateLookupLevels(table_path, table_schema, processor_factory, + std::vector>{ + level0_file, high_level_file})); + ASSERT_OK_AND_ASSIGN(auto rewriter, + CreateCompactRewriterForFirstRow(table_path, table_schema, core_options, + std::move(lookup_levels))); + ASSERT_OK_AND_ASSIGN( + auto runs, GenerateSortedRuns(std::vector>{level0_file})); + ASSERT_OK_AND_ASSIGN(auto compact_result, rewriter->Rewrite( + /*output_level=*/1, /*drop_delete=*/true, runs)); + + ASSERT_EQ(1, compact_result.After().size()); + ASSERT_EQ(1, compact_result.After()[0]->row_count); + + auto type_with_special_fields = + arrow::struct_(SpecialFields::CompleteSequenceAndValueKindField(arrow_schema_)->fields()); + std::shared_ptr expected; + ASSERT_TRUE(arrow::ipc::internal::json::ChunkedArrayFromJSON(type_with_special_fields, + {"[[2, 0, 2, 22]]"}, &expected) + .ok()); + CheckResult(table_path + "/bucket-0/" + compact_result.After()[0]->file_name, table_schema, + "orc", expected); +} + TEST_F(LookupMergeTreeCompactRewriterTest, TestFirstRowUpgrade) { std::map options = {{Options::MERGE_ENGINE, "first-row"}, {Options::FILE_FORMAT, "orc"}}; diff --git a/src/paimon/core/mergetree/lookup_levels.cpp b/src/paimon/core/mergetree/lookup_levels.cpp index 8b5f69e77..a931fea10 100644 --- a/src/paimon/core/mergetree/lookup_levels.cpp +++ b/src/paimon/core/mergetree/lookup_levels.cpp @@ -162,8 +162,8 @@ LookupLevels::LookupLevels( lookup_store_factory_(lookup_store_factory), lookup_file_cache_(lookup_file_cache), remote_lookup_file_manager_(remote_lookup_file_manager) { - if constexpr (std::is_same_v) { - // if T is FilePosition, only read key fields to create sst file is enough + if constexpr (std::is_same_v || std::is_same_v) { + // FilePosition and first-row lookup do not persist values, so reading key fields is enough. value_schema_ = key_schema_; } else { value_schema_ = DataField::ConvertDataFieldsToArrowSchema(table_schema->Fields()); @@ -332,16 +332,6 @@ std::optional LookupLevels::TryToDownloadRemoteSst( template Status LookupLevels::CreateSstFileFromDataFile(const std::shared_ptr& file, const std::string& kv_file_path) { - if constexpr (std::is_same_v) { - // Short-circuit logic: if T is bool, just write empty lookup file. - PAIMON_ASSIGN_OR_RAISE( - std::shared_ptr bloom_filter, - LookupStoreFactory::BfGenerator(file->row_count, options_, pool_.get())); - PAIMON_ASSIGN_OR_RAISE( - std::unique_ptr kv_writer, - lookup_store_factory_->CreateWriter(fs_, kv_file_path, bloom_filter, pool_)); - return kv_writer->Close(); - } // Prepare reader to iterate KeyValue PAIMON_ASSIGN_OR_RAISE( std::vector> raw_readers,