This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 5ef21b7216 [core] Skip DV reads for file-index-rejected single files 
(#10287)
5ef21b7216 is described below

commit 5ef21b7216e38042292c2a3c913a50d5b7974038
Author: sanshi <[email protected]>
AuthorDate: Fri Oct 2 09:45:54 2026 +0800

    [core] Skip DV reads for file-index-rejected single files (#10287)
---
 .../paimon/operation/DataEvolutionSplitRead.java   | 76 ++++++++++++++++++++--
 .../paimon/table/DataEvolutionFileIndexTest.java   | 22 +++++++
 2 files changed, 94 insertions(+), 4 deletions(-)

diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
 
b/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
index 60902d352a..470a15f4a5 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/DataEvolutionSplitRead.java
@@ -236,16 +236,39 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
                 // No need to merge fields, just create a single file reader
                 suppliers.add(
                         () -> {
+                            DataFileMeta file = needMergeFiles.get(0);
+                            FileIndexResult fileIndexResult =
+                                    evaluateFileIndex(filters, file, 
dataFilePathFactory);
+                            if (fileIndexResult != null && 
!fileIndexResult.remain()) {
+                                return new EmptyFileRecordReader<>();
+                            }
                             DeletionVectorWithRange deletionVector =
                                     readDeletionVector(needMergeFiles, 
deletionVectorFactory);
+                            if (fileIndexResult != null
+                                    && deletionVector != null
+                                    && 
!deletionVector.deletionVector.isEmpty()) {
+                                fileIndexResult =
+                                        
FileIndexEvaluator.intersectDeletionVector(
+                                                fileIndexResult,
+                                                file,
+                                                deletionVector.deletionVector,
+                                                deletionVectorOffset(
+                                                        
file.nonNullRowIdRange(),
+                                                        rowRanges,
+                                                        deletionVector));
+                                if (!fileIndexResult.remain()) {
+                                    return new EmptyFileRecordReader<>();
+                                }
+                            }
                             return createFileReader(
                                     partition,
                                     dataFilePathFactory,
-                                    needMergeFiles.get(0),
+                                    file,
                                     filters,
                                     rowRanges,
                                     readRowType,
-                                    deletionVector);
+                                    deletionVector,
+                                    fileIndexResult);
                         });
 
             } else {
@@ -675,6 +698,27 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
             RowType readRowType,
             @Nullable DeletionVectorWithRange deletionVector)
             throws IOException {
+        return createFileReader(
+                partition,
+                dataFilePathFactory,
+                file,
+                filters,
+                rowRanges,
+                readRowType,
+                deletionVector,
+                null);
+    }
+
+    private FileRecordReader<InternalRow> createFileReader(
+            BinaryRow partition,
+            DataFilePathFactory dataFilePathFactory,
+            DataFileMeta file,
+            @Nullable List<Predicate> filters,
+            List<Range> rowRanges,
+            RowType readRowType,
+            @Nullable DeletionVectorWithRange deletionVector,
+            @Nullable FileIndexResult precomputedFileIndexResult)
+            throws IOException {
         FileReadTarget readTarget = readTarget(file, dataFilePathFactory, 
rowRanges);
         String formatIdentifier = readTarget.formatIdentifier;
         long schemaId = file.schemaId();
@@ -696,8 +740,8 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
                                 formatBuilder(readRowType, fileFilters, 
nestedFieldEnabled)
                                         .build(formatIdentifier, schema, 
dataSchema));
 
-        FileIndexResult fileIndexResult = null;
-        if (fileIndexReadEnabled) {
+        FileIndexResult fileIndexResult = precomputedFileIndexResult;
+        if (fileIndexResult == null && fileIndexReadEnabled) {
             DeletionVector dv = deletionVector == null ? null : 
deletionVector.deletionVector;
             long fileOffset =
                     dv == null || dv.isEmpty()
@@ -870,6 +914,30 @@ public class DataEvolutionSplitRead implements 
SplitRead<InternalRow> {
         return true;
     }
 
+    @Nullable
+    private FileIndexResult evaluateFileIndex(
+            @Nullable List<Predicate> filters,
+            DataFileMeta file,
+            DataFilePathFactory dataFilePathFactory)
+            throws IOException {
+        if (!fileIndexReadEnabled) {
+            return null;
+        }
+
+        long schemaId = file.schemaId();
+        TableSchema dataSchema = schemaId == schema.id() ? schema : 
schemaFetcher.apply(schemaId);
+        List<Predicate> fileFilters = fileFilters(filters, file);
+        return FileIndexEvaluator.evaluate(
+                fileIO,
+                dataSchema,
+                devolveFilters(fileFilters, dataSchema),
+                null,
+                null,
+                dataFilePathFactory,
+                file,
+                null);
+    }
+
     /**
      * Evaluates each applicable file index once for the winning fields of a 
merged row-id group.
      *
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
index c350c424f6..e323817166 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionFileIndexTest.java
@@ -556,6 +556,28 @@ public class DataEvolutionFileIndexTest extends 
DataEvolutionTestBase {
         assertThat(rowIds(rows)).containsExactly(50L);
     }
 
+    @Test
+    public void testSingleFileIndexSkipsBeforeReadingDeletionVector() throws 
Exception {
+        Map<String, String> options = bitmapOptions("f1");
+        options.put(CoreOptions.DELETION_VECTORS_ENABLED.key(), "true");
+        FileStoreTable table = createTable("single_bitmap_before_dv", options);
+        writeAllColumns(table, ROW_COUNT);
+        deleteRows(table, 50);
+
+        FileStoreTable latest = getTable(identifier(table.name()));
+        DataSplit split = (DataSplit) 
latest.newReadBuilder().newScan().plan().splits().get(0);
+        Path deletionVectorPath =
+                split.deletionFiles().get().stream()
+                        .filter(Objects::nonNull)
+                        .map(file -> new Path(file.path()))
+                        .findFirst()
+                        .orElseThrow(IllegalStateException::new);
+        assertThat(latest.fileIO().delete(deletionVectorPath, false)).isTrue();
+
+        // The bitmap index already rejects this value, so the missing DV file 
must not be read.
+        assertThat(readWithFilter(table, equalF1(MISSING_F1))).isEmpty();
+    }
+
     @Test
     public void testMergedGroupKeptWhenFilterColumnOverwritten() throws 
Exception {
         FileStoreTable table = createTable("overwritten", 
Collections.emptyMap());

Reply via email to