2222#include < cassert>
2323#include < limits>
2424#include < map>
25+ #include < set>
2526#include < string>
2627#include < string_view>
2728#include < thread>
5354#include " paimon/core/core_options.h"
5455#include " paimon/core/deletionvectors/apply_deletion_vector_batch_reader.h"
5556#include " paimon/core/global_index/indexed_split_impl.h"
57+ #include " paimon/core/io/file_index_evaluator.h"
5658#include " paimon/core/utils/blob_view_lookup.h"
5759#include " paimon/core/utils/data_evolution_utils.h"
60+ #include " paimon/core/utils/field_mapping.h"
61+ #include " paimon/file_index/bitmap_index_result.h"
62+ #include " paimon/file_index/file_index_result.h"
63+ #include " paimon/predicate/predicate_utils.h"
5864
5965namespace paimon {
6066namespace {
@@ -389,12 +395,22 @@ Result<std::unique_ptr<BatchReader>> DataEvolutionSplitRead::InnerCreateReader(
389395 path_factory_->CreateDataFilePathFactory (split_impl->Partition (), split_impl->Bucket ()));
390396 auto metas = split_impl->DataFiles ();
391397 DeletionVector::Factory split_dv_factory = CreateSplitDvFactory (*split_impl);
398+ PAIMON_ASSIGN_OR_RAISE (std::shared_ptr<Predicate> push_down_predicate,
399+ CreatePushDownPredicate (context_->GetPredicate (), raw_read_schema_));
392400
393401 PAIMON_ASSIGN_OR_RAISE (std::vector<std::vector<std::shared_ptr<DataFileMeta>>> split_by_row_id,
394402 MergeRangesAndSort (std::move (metas)));
395403
396404 std::vector<std::unique_ptr<BatchReader>> sub_readers;
397405 for (const std::vector<std::shared_ptr<DataFileMeta>>& need_merge_files : split_by_row_id) {
406+ if (need_merge_files.size () > 1 ) {
407+ PAIMON_ASSIGN_OR_RAISE (
408+ bool skip_group,
409+ SkipByFileIndex (push_down_predicate, need_merge_files, data_file_path_factory));
410+ if (skip_group) {
411+ continue ;
412+ }
413+ }
398414 PAIMON_ASSIGN_OR_RAISE (std::optional<GroupDeletionVector> group_dv,
399415 ReadGroupDeletionVector (need_merge_files, split_dv_factory));
400416 PAIMON_ASSIGN_OR_RAISE (DeletionVector::Factory group_dv_factory,
@@ -404,10 +420,15 @@ Result<std::unique_ptr<BatchReader>> DataEvolutionSplitRead::InnerCreateReader(
404420 PAIMON_ASSIGN_OR_RAISE (
405421 std::vector<std::unique_ptr<FileBatchReader>> raw_file_readers,
406422 CreateRawFileReaders (split_impl->Partition (), need_merge_files, raw_read_schema_,
407- /* predicate= */ nullptr , group_dv_factory, row_ranges,
423+ push_down_predicate , group_dv_factory, row_ranges,
408424 data_file_path_factory,
409425 /* extra_format_options=*/ {}));
410- assert (raw_file_readers.size () == 1 );
426+ if (raw_file_readers.empty ()) {
427+ continue ;
428+ }
429+ if (raw_file_readers.size () != 1 ) {
430+ return Status::Invalid (" Single-file data evolution group created multiple readers" );
431+ }
411432 sub_readers.push_back (std::move (raw_file_readers[0 ]));
412433 } else {
413434 PAIMON_ASSIGN_OR_RAISE (
@@ -424,17 +445,110 @@ Result<std::unique_ptr<BatchReader>> DataEvolutionSplitRead::InnerCreateReader(
424445 return std::make_unique<CompleteRowKindBatchReader>(std::move (batch_reader), pool_);
425446}
426447
448+ Result<std::shared_ptr<Predicate>> DataEvolutionSplitRead::CreatePushDownPredicate (
449+ const std::shared_ptr<Predicate>& predicate,
450+ const std::shared_ptr<arrow::Schema>& read_schema) {
451+ std::map<std::string, int32_t > picked_field_name_to_idx;
452+ for (int32_t i = 0 ; i < read_schema->num_fields (); ++i) {
453+ const std::string& field_name = read_schema->field (i)->name ();
454+ if (!SpecialFields::IsSystemField (field_name)) {
455+ picked_field_name_to_idx.emplace (field_name, i);
456+ }
457+ }
458+ return PredicateUtils::CreatePickedFieldFilter (predicate, picked_field_name_to_idx);
459+ }
460+
461+ Result<bool > DataEvolutionSplitRead::SkipByFileIndex (
462+ const std::shared_ptr<Predicate>& predicate,
463+ const std::vector<std::shared_ptr<DataFileMeta>>& files,
464+ const std::shared_ptr<DataFilePathFactory>& data_file_path_factory) const {
465+ if (!options_.FileIndexReadEnabled () || !predicate) {
466+ return false ;
467+ }
468+
469+ PAIMON_ASSIGN_OR_RAISE (
470+ std::unique_ptr<FieldMappingBuilder> field_mapping_builder,
471+ FieldMappingBuilder::Create (raw_read_schema_, context_->GetPartitionKeys (), predicate));
472+ std::set<int32_t > claimed_field_ids;
473+ for (const auto & file : files) {
474+ // Blob and vector-store files may cover only part of the row range, so their indexes
475+ // cannot prove that the complete merged group misses the predicate.
476+ if (!DataEvolutionUtils::IsNormalFile (file->file_name )) {
477+ continue ;
478+ }
479+
480+ std::shared_ptr<TableSchema> data_schema = context_->GetTableSchema ();
481+ if (file->schema_id != data_schema->Id ()) {
482+ PAIMON_ASSIGN_OR_RAISE (data_schema, schema_manager_->ReadSchema (file->schema_id ));
483+ }
484+ std::vector<DataField> written_fields;
485+ if (file->write_cols ) {
486+ std::vector<std::string> data_write_cols;
487+ data_write_cols.reserve (file->write_cols ->size ());
488+ for (const auto & write_col : file->write_cols .value ()) {
489+ if (!SpecialFields::IsSystemField (write_col)) {
490+ data_write_cols.push_back (write_col);
491+ }
492+ }
493+ PAIMON_ASSIGN_OR_RAISE (written_fields, data_schema->GetFields (data_write_cols));
494+ } else {
495+ written_fields = data_schema->Fields ();
496+ }
497+
498+ std::set<std::string> overwritten_field_names;
499+ for (const auto & field : written_fields) {
500+ if (!claimed_field_ids.insert (field.Id ()).second ) {
501+ overwritten_field_names.insert (field.Name ());
502+ }
503+ }
504+
505+ PAIMON_ASSIGN_OR_RAISE (std::unique_ptr<FieldMapping> field_mapping,
506+ field_mapping_builder->CreateFieldMapping (written_fields));
507+ std::shared_ptr<Predicate> data_predicate =
508+ field_mapping->non_partition_info .non_partition_filter ;
509+ if (!overwritten_field_names.empty ()) {
510+ PAIMON_ASSIGN_OR_RAISE (data_predicate, PredicateUtils::ExcludePredicateWithFields (
511+ data_predicate, overwritten_field_names));
512+ }
513+ if (!data_predicate) {
514+ continue ;
515+ }
516+
517+ auto written_schema = DataField::ConvertDataFieldsToArrowSchema (written_fields);
518+ PAIMON_ASSIGN_OR_RAISE (
519+ std::shared_ptr<FileIndexResult> index_result,
520+ FileIndexEvaluator::Evaluate (written_schema, data_predicate, data_file_path_factory,
521+ file, options_.GetFileSystem (), pool_));
522+ PAIMON_ASSIGN_OR_RAISE (bool is_remain, index_result->IsRemain ());
523+ if (!is_remain) {
524+ return true ;
525+ }
526+ }
527+ return false ;
528+ }
529+
427530Result<std::unique_ptr<FileBatchReader>> DataEvolutionSplitRead::ApplyIndexAndDvReaderIfNeeded (
428531 std::unique_ptr<FileBatchReader>&& file_reader, const std::shared_ptr<DataFileMeta>& file,
429532 const std::shared_ptr<arrow::Schema>& data_schema,
430533 const std::shared_ptr<arrow::Schema>& read_schema, const std::shared_ptr<Predicate>& predicate,
431534 DeletionVector::Factory dv_factory, const std::optional<std::vector<Range>>& row_ranges,
432535 const std::shared_ptr<DataFilePathFactory>& data_file_path_factory) const {
433- if (predicate) {
434- assert (false );
435- // as DataEvolutionSplitRead will skip predicate
436- return Status::Invalid (" DataEvolutionSplitRead do not support predicate" );
536+ std::shared_ptr<FileIndexResult> file_index_result;
537+ if (options_.FileIndexReadEnabled ()) {
538+ PAIMON_ASSIGN_OR_RAISE (
539+ file_index_result,
540+ FileIndexEvaluator::Evaluate (data_schema, predicate, data_file_path_factory, file,
541+ options_.GetFileSystem (), pool_));
542+ PAIMON_ASSIGN_OR_RAISE (bool is_remain, file_index_result->IsRemain ());
543+ if (!is_remain) {
544+ return std::unique_ptr<FileBatchReader>();
545+ }
546+ }
547+ const RoaringBitmap32* index_selection = nullptr ;
548+ if (auto * bitmap_index = dynamic_cast <BitmapIndexResult*>(file_index_result.get ())) {
549+ PAIMON_ASSIGN_OR_RAISE (index_selection, bitmap_index->GetBitmap ());
437550 }
551+
438552 // the factory is per row range group and already returns a view taking file-local positions.
439553 // Unlike RawFileSplitRead the vector is not folded into the format reader's selection: it is
440554 // no BitmapDeletionVector, and the blob fallback path's gap segments have no format reader.
@@ -444,10 +558,19 @@ Result<std::unique_ptr<FileBatchReader>> DataEvolutionSplitRead::ApplyIndexAndDv
444558 }
445559 PAIMON_ASSIGN_OR_RAISE (std::optional<RoaringBitmap32> selection_row_ids,
446560 file->ToFileSelection (row_ranges));
561+ if (index_selection) {
562+ if (selection_row_ids) {
563+ selection_row_ids.value () &= *index_selection;
564+ } else {
565+ selection_row_ids = *index_selection;
566+ }
567+ }
568+ if (selection_row_ids && selection_row_ids->IsEmpty ()) {
569+ return std::unique_ptr<FileBatchReader>();
570+ }
447571 ::ArrowSchema c_read_schema;
448572 PAIMON_RETURN_NOT_OK_FROM_ARROW (arrow::ExportSchema (*read_schema, &c_read_schema));
449- PAIMON_RETURN_NOT_OK (
450- file_reader->SetReadSchema (&c_read_schema, /* predicate=*/ nullptr , selection_row_ids));
573+ PAIMON_RETURN_NOT_OK (file_reader->SetReadSchema (&c_read_schema, predicate, selection_row_ids));
451574
452575 std::unique_ptr<FileBatchReader> reader;
453576 if (!file_reader->SupportPreciseBitmapSelection () && selection_row_ids) {
0 commit comments