1919#include " paimon/core/operation/raw_file_split_read.h"
2020
2121#include < cstdint>
22+ #include < limits>
2223#include < map>
2324#include < optional>
2425#include < set>
@@ -225,11 +226,6 @@ auto RawFileSplitRead::TryCreateLateMaterializedReader(
225226 if (!plan) {
226227 return LateMaterializationReadResult ();
227228 }
228- for (const auto & file : data_files) {
229- if (!file->first_row_id ) {
230- return LateMaterializationReadResult ();
231- }
232- }
233229
234230 std::map<std::string, int32_t > probe_field_name_to_idx;
235231 for (int32_t i = 0 ; i < plan->probe_schema ->num_fields (); ++i) {
@@ -261,7 +257,7 @@ auto RawFileSplitRead::TryCreateLateMaterializedReader(
261257 }
262258
263259 std::vector<std::shared_ptr<arrow::Array>> probe_chunks;
264- std::vector<Range> selected_global_ranges ;
260+ RoaringBitmap32 selected_file_rows ;
265261 while (true ) {
266262 PAIMON_ASSIGN_OR_RAISE (BatchReader::ReadBatchWithBitmap batch_with_bitmap,
267263 probe_readers[0 ]->NextBatchWithBitmap ());
@@ -297,9 +293,12 @@ auto RawFileSplitRead::TryCreateLateMaterializedReader(
297293 }
298294 PAIMON_ASSIGN_OR_RAISE (uint64_t file_row_id,
299295 probe_readers[0 ]->GetPreviousBatchFileRowId (batch_row_id));
300- int64_t global_row_id =
301- file->first_row_id .value () + static_cast <int64_t >(file_row_id);
302- selected_global_ranges.emplace_back (global_row_id, global_row_id);
296+ if (file_row_id > std::numeric_limits<uint32_t >::max ()) {
297+ return Status::Invalid (
298+ fmt::format (" late materialization file row id {} exceeds bitmap capacity" ,
299+ file_row_id));
300+ }
301+ selected_file_rows.Add (static_cast <uint32_t >(file_row_id));
303302 selected_bitmap.Add (batch_row_id);
304303 }
305304
@@ -326,7 +325,7 @@ auto RawFileSplitRead::TryCreateLateMaterializedReader(
326325 completed_metrics->Merge (probe_readers[0 ]->GetReaderMetrics ());
327326 probe_readers[0 ]->Close ();
328327
329- if (selected_global_ranges. empty ()) {
328+ if (selected_file_rows. IsEmpty ()) {
330329 continue ;
331330 }
332331
@@ -335,13 +334,12 @@ auto RawFileSplitRead::TryCreateLateMaterializedReader(
335334 arrow::Concatenate (probe_chunks, probe_arrow_pool.get ()));
336335 std::shared_ptr<arrow::StructArray> probe_struct =
337336 arrow::internal::checked_pointer_cast<arrow::StructArray>(probe_data);
338- std::vector<Range> row_ranges =
339- Range::SortAndMergeOverlap (selected_global_ranges, /* adjacent=*/ true );
340337 PAIMON_ASSIGN_OR_RAISE (
341338 std::vector<std::unique_ptr<FileBatchReader>> payload_readers,
342339 CreateRawFileReaders (partition, {file}, plan->payload_schema ,
343- /* predicate=*/ nullptr , dv_factory, row_ranges,
344- data_file_path_factory, /* extra_format_options=*/ {}));
340+ /* predicate=*/ nullptr , dv_factory,
341+ /* row_ranges=*/ std::nullopt , data_file_path_factory,
342+ /* extra_format_options=*/ {}, selected_file_rows));
345343 if (payload_readers.empty ()) {
346344 return Status::Invalid (" late materialization payload reader was filtered out" );
347345 }
@@ -367,7 +365,8 @@ Result<std::unique_ptr<FileBatchReader>> RawFileSplitRead::ApplyIndexAndDvReader
367365 const std::shared_ptr<arrow::Schema>& data_schema,
368366 const std::shared_ptr<arrow::Schema>& read_schema, const std::shared_ptr<Predicate>& predicate,
369367 DeletionVector::Factory dv_factory, const std::optional<std::vector<Range>>& ranges,
370- const std::shared_ptr<DataFilePathFactory>& data_file_path_factory) const {
368+ const std::shared_ptr<DataFilePathFactory>& data_file_path_factory,
369+ const std::optional<RoaringBitmap32>& file_selection) const {
371370 std::shared_ptr<FileIndexResult> file_index_result;
372371 if (options_.FileIndexReadEnabled ()) {
373372 PAIMON_ASSIGN_OR_RAISE (
@@ -420,6 +419,14 @@ Result<std::unique_ptr<FileBatchReader>> RawFileSplitRead::ApplyIndexAndDvReader
420419 }
421420 }
422421
422+ // Late materialization already operates on one FileBatchReader at a time, so its selection
423+ // can stay file-local instead of making a round trip through global row IDs.
424+ if (file_selection) {
425+ actual_selection = actual_selection ? RoaringBitmap32::And (actual_selection.value (),
426+ file_selection.value ())
427+ : file_selection;
428+ }
429+
423430 if (actual_selection && actual_selection.value ().IsEmpty ()) {
424431 return std::unique_ptr<FileBatchReader>();
425432 }
0 commit comments