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

lzljs3620320 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 4cbbb99935 [core] Add serializer/deserialize for GlobalIndexResult 
(#6810)
4cbbb99935 is described below

commit 4cbbb99935adf21f41133f20233e39eef4031a17
Author: YeJunHao <[email protected]>
AuthorDate: Fri Dec 12 20:20:42 2025 +0800

    [core] Add serializer/deserialize for GlobalIndexResult (#6810)
---
 .../globalindex/GlobalIndexResultSerializer.java   | 119 ++++++++++++++++++++
 .../paimon/globalindex/TopkGlobalIndexResult.java  |  56 ++++++++++
 .../apache/paimon/utils/RoaringNavigableMap64.java |  16 ++-
 .../globalindex/GlobalIndexSerDeUtilsTest.java     | 121 +++++++++++++++++++++
 .../paimon/utils/RoaringNavigableMap64Test.java    | 111 +++++++++++++++++++
 .../paimon/globalindex/DataEvolutionBatchScan.java |  19 +++-
 .../paimon/table/DataEvolutionTableTest.java       |  10 +-
 7 files changed, 441 insertions(+), 11 deletions(-)

diff --git 
a/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexResultSerializer.java
 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexResultSerializer.java
new file mode 100644
index 0000000000..5253b59522
--- /dev/null
+++ 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexResultSerializer.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.globalindex;
+
+import org.apache.paimon.data.serializer.Serializer;
+import org.apache.paimon.io.DataInputDeserializer;
+import org.apache.paimon.io.DataInputView;
+import org.apache.paimon.io.DataOutputSerializer;
+import org.apache.paimon.io.DataOutputView;
+import org.apache.paimon.utils.RoaringNavigableMap64;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.paimon.utils.Preconditions.checkArgument;
+
+/** GlobalIndexResultSerializer to serialize and deserialize 
GlobalIndexResult. */
+public class GlobalIndexResultSerializer implements 
Serializer<GlobalIndexResult> {
+
+    private static final int VERSION = 1;
+
+    @Override
+    public Serializer<GlobalIndexResult> duplicate() {
+        return this;
+    }
+
+    @Override
+    public GlobalIndexResult copy(GlobalIndexResult from) {
+        try {
+            DataOutputSerializer dataOutputSerializer = new 
DataOutputSerializer(1024);
+            serialize(from, dataOutputSerializer);
+
+            DataInputDeserializer dataInputDeserializer =
+                    new 
DataInputDeserializer(dataOutputSerializer.getCopyOfBuffer());
+            return deserialize(dataInputDeserializer);
+        } catch (IOException e) {
+            throw new RuntimeException("Copy failed", e);
+        }
+    }
+
+    @Override
+    public void serialize(GlobalIndexResult globalIndexResult, DataOutputView 
dataOutput)
+            throws IOException {
+        dataOutput.writeInt(VERSION);
+
+        RoaringNavigableMap64 roaringNavigableMap64 = 
globalIndexResult.results();
+        byte[] bytes = roaringNavigableMap64.serialize();
+
+        dataOutput.writeInt(bytes.length);
+        dataOutput.write(bytes);
+
+        if (globalIndexResult instanceof TopkGlobalIndexResult) {
+            TopkGlobalIndexResult topkGlobalIndexResult = 
(TopkGlobalIndexResult) globalIndexResult;
+            dataOutput.writeInt(roaringNavigableMap64.getIntCardinality());
+            ScoreGetter scoreGetter = topkGlobalIndexResult.scoreGetter();
+            for (Long rowId : roaringNavigableMap64) {
+                dataOutput.writeFloat(scoreGetter.score(rowId));
+            }
+        } else {
+            dataOutput.writeInt(0);
+        }
+    }
+
+    @Override
+    public GlobalIndexResult deserialize(DataInputView dataInput) throws 
IOException {
+        int version = dataInput.readInt();
+        if (version != VERSION) {
+            throw new IllegalStateException("Invalid version: " + version);
+        }
+
+        int size = dataInput.readInt();
+        byte[] bytes = new byte[size];
+        dataInput.readFully(bytes);
+
+        RoaringNavigableMap64 roaringNavigableMap64 = new 
RoaringNavigableMap64();
+        roaringNavigableMap64.deserialize(bytes);
+        int scoreSize = dataInput.readInt();
+
+        if (scoreSize == 0) {
+            return GlobalIndexResult.create(() -> roaringNavigableMap64);
+        }
+        checkArgument(
+                scoreSize == roaringNavigableMap64.getIntCardinality(),
+                "Error size of score: "
+                        + scoreSize
+                        + ", expected: "
+                        + roaringNavigableMap64.getIntCardinality());
+
+        float[] scores = new float[scoreSize];
+        for (int i = 0; i < scoreSize; i++) {
+            scores[i] = dataInput.readFloat();
+        }
+
+        Map<Long, Float> scoreMap = new HashMap<>();
+        int i = 0;
+        for (Long rowId : roaringNavigableMap64) {
+            scoreMap.put(rowId, scores[i++]);
+        }
+
+        return TopkGlobalIndexResult.create(() -> roaringNavigableMap64, 
scoreMap::get);
+    }
+}
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/globalindex/TopkGlobalIndexResult.java
 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/TopkGlobalIndexResult.java
index 12e15260f4..eaac93fa75 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/globalindex/TopkGlobalIndexResult.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/globalindex/TopkGlobalIndexResult.java
@@ -18,8 +18,64 @@
 
 package org.apache.paimon.globalindex;
 
+import org.apache.paimon.utils.LazyField;
+import org.apache.paimon.utils.RoaringNavigableMap64;
+
+import java.util.function.Supplier;
+
 /** Top-k global index result for vector index. */
 public interface TopkGlobalIndexResult extends GlobalIndexResult {
 
     ScoreGetter scoreGetter();
+
+    default GlobalIndexResult and(GlobalIndexResult other) {
+        throw new UnsupportedOperationException("Please realize this by 
specified global index");
+    }
+
+    @Override
+    default GlobalIndexResult or(GlobalIndexResult other) {
+        if (!(other instanceof TopkGlobalIndexResult)) {
+            return GlobalIndexResult.super.or(other);
+        }
+        RoaringNavigableMap64 thisRowIds = results();
+        ScoreGetter thisScoreGetter = scoreGetter();
+
+        RoaringNavigableMap64 otherRowIds = other.results();
+        ScoreGetter otherScoreGetter = ((TopkGlobalIndexResult) 
other).scoreGetter();
+
+        final RoaringNavigableMap64 resultOr = 
RoaringNavigableMap64.or(thisRowIds, otherRowIds);
+        return new TopkGlobalIndexResult() {
+            @Override
+            public ScoreGetter scoreGetter() {
+                return rowId -> {
+                    if (thisRowIds.contains(rowId)) {
+                        return thisScoreGetter.score(rowId);
+                    }
+                    return otherScoreGetter.score(rowId);
+                };
+            }
+
+            @Override
+            public RoaringNavigableMap64 results() {
+                return resultOr;
+            }
+        };
+    }
+
+    /** Returns a new {@link TopkGlobalIndexResult} from supplier. */
+    static TopkGlobalIndexResult create(
+            Supplier<RoaringNavigableMap64> supplier, ScoreGetter scoreGetter) 
{
+        LazyField<RoaringNavigableMap64> lazyField = new LazyField<>(supplier);
+        return new TopkGlobalIndexResult() {
+            @Override
+            public ScoreGetter scoreGetter() {
+                return scoreGetter;
+            }
+
+            @Override
+            public RoaringNavigableMap64 results() {
+                return lazyField.get();
+            }
+        };
+    }
 }
diff --git 
a/paimon-common/src/main/java/org/apache/paimon/utils/RoaringNavigableMap64.java
 
b/paimon-common/src/main/java/org/apache/paimon/utils/RoaringNavigableMap64.java
index 6bb52af3d3..e61486ecc4 100644
--- 
a/paimon-common/src/main/java/org/apache/paimon/utils/RoaringNavigableMap64.java
+++ 
b/paimon-common/src/main/java/org/apache/paimon/utils/RoaringNavigableMap64.java
@@ -33,7 +33,7 @@ import java.util.List;
 import java.util.Objects;
 
 /** A compressed bitmap for 64-bit integer aggregated by tree. */
-public class RoaringNavigableMap64 {
+public class RoaringNavigableMap64 implements Iterable<Long> {
 
     private final Roaring64NavigableMap roaring64NavigableMap;
 
@@ -46,11 +46,11 @@ public class RoaringNavigableMap64 {
     }
 
     public void addRange(Range range) {
-        if (range.from == range.to) {
-            roaring64NavigableMap.add(range.from);
-        } else {
-            roaring64NavigableMap.addRange(range.from, range.to);
-        }
+        roaring64NavigableMap.addRange(range.from, range.to + 1);
+    }
+
+    public boolean contains(long x) {
+        return roaring64NavigableMap.contains(x);
     }
 
     public void add(long x) {
@@ -77,6 +77,10 @@ public class RoaringNavigableMap64 {
         return roaring64NavigableMap.getLongCardinality();
     }
 
+    public int getIntCardinality() {
+        return roaring64NavigableMap.getIntCardinality();
+    }
+
     public Iterator<Long> iterator() {
         return roaring64NavigableMap.iterator();
     }
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexSerDeUtilsTest.java
 
b/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexSerDeUtilsTest.java
new file mode 100644
index 0000000000..a5aaa74e87
--- /dev/null
+++ 
b/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexSerDeUtilsTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.globalindex;
+
+import org.apache.paimon.io.DataInputDeserializer;
+import org.apache.paimon.io.DataOutputSerializer;
+import org.apache.paimon.utils.RoaringNavigableMap64;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link GlobalIndexResultSerializer}. */
+public class GlobalIndexSerDeUtilsTest {
+
+    @Test
+    public void testSerializeAndDeserializeGlobalIndexResult() throws 
IOException {
+        RoaringNavigableMap64 bitmap = RoaringNavigableMap64.bitmapOf(1, 5, 
10, 100, 1000);
+        GlobalIndexResult original = GlobalIndexResult.create(() -> bitmap);
+
+        byte[] serialized = serialize(original);
+        GlobalIndexResult deserialized = deserialize(serialized);
+
+        assertThat(deserialized).isNotInstanceOf(TopkGlobalIndexResult.class);
+        assertThat(deserialized.results()).isEqualTo(bitmap);
+    }
+
+    @Test
+    public void testSerializeAndDeserializeEmptyGlobalIndexResult() throws 
IOException {
+        GlobalIndexResult original = GlobalIndexResult.createEmpty();
+
+        byte[] serialized = serialize(original);
+        GlobalIndexResult deserialized = deserialize(serialized);
+
+        assertThat(deserialized).isNotInstanceOf(TopkGlobalIndexResult.class);
+        assertThat(deserialized.results().isEmpty()).isTrue();
+    }
+
+    @Test
+    public void testSerializeAndDeserializeTopkGlobalIndexResult() throws 
IOException {
+        RoaringNavigableMap64 bitmap = RoaringNavigableMap64.bitmapOf(1, 5, 
10, 100);
+        Map<Long, Float> scoreMap = new HashMap<>();
+        scoreMap.put(1L, 0.9f);
+        scoreMap.put(5L, 0.8f);
+        scoreMap.put(10L, 0.7f);
+        scoreMap.put(100L, 0.6f);
+
+        TopkGlobalIndexResult original = TopkGlobalIndexResult.create(() -> 
bitmap, scoreMap::get);
+
+        byte[] serialized = serialize(original);
+        GlobalIndexResult deserialized = deserialize(serialized);
+
+        assertThat(deserialized).isInstanceOf(TopkGlobalIndexResult.class);
+        assertThat(deserialized.results()).isEqualTo(bitmap);
+
+        TopkGlobalIndexResult topkResult = (TopkGlobalIndexResult) 
deserialized;
+        ScoreGetter scoreGetter = topkResult.scoreGetter();
+        assertThat(scoreGetter.score(1L)).isEqualTo(0.9f);
+        assertThat(scoreGetter.score(5L)).isEqualTo(0.8f);
+        assertThat(scoreGetter.score(10L)).isEqualTo(0.7f);
+        assertThat(scoreGetter.score(100L)).isEqualTo(0.6f);
+    }
+
+    @Test
+    public void testSerializeAndDeserializeTopkWithLargeRowIds() throws 
IOException {
+        RoaringNavigableMap64 bitmap =
+                RoaringNavigableMap64.bitmapOf(
+                        Integer.MAX_VALUE + 1L, Integer.MAX_VALUE + 100L, 
Long.MAX_VALUE - 1);
+        Map<Long, Float> scoreMap = new HashMap<>();
+        scoreMap.put(Integer.MAX_VALUE + 1L, 0.5f);
+        scoreMap.put(Integer.MAX_VALUE + 100L, 0.3f);
+        scoreMap.put(Long.MAX_VALUE - 1, 0.1f);
+
+        TopkGlobalIndexResult original = TopkGlobalIndexResult.create(() -> 
bitmap, scoreMap::get);
+
+        byte[] serialized = serialize(original);
+        GlobalIndexResult deserialized = deserialize(serialized);
+
+        assertThat(deserialized).isInstanceOf(TopkGlobalIndexResult.class);
+        assertThat(deserialized.results()).isEqualTo(bitmap);
+
+        TopkGlobalIndexResult topkResult = (TopkGlobalIndexResult) 
deserialized;
+        ScoreGetter scoreGetter = topkResult.scoreGetter();
+        assertThat(scoreGetter.score(Integer.MAX_VALUE + 1L)).isEqualTo(0.5f);
+        assertThat(scoreGetter.score(Integer.MAX_VALUE + 
100L)).isEqualTo(0.3f);
+        assertThat(scoreGetter.score(Long.MAX_VALUE - 1)).isEqualTo(0.1f);
+    }
+
+    private byte[] serialize(GlobalIndexResult result) throws IOException {
+        GlobalIndexResultSerializer globalIndexResultSerializer = new 
GlobalIndexResultSerializer();
+        DataOutputSerializer dataOutputSerializer = new 
DataOutputSerializer(1024);
+        globalIndexResultSerializer.serialize(result, dataOutputSerializer);
+        return dataOutputSerializer.getCopyOfBuffer();
+    }
+
+    private GlobalIndexResult deserialize(byte[] data) throws IOException {
+        GlobalIndexResultSerializer globalIndexResultSerializer = new 
GlobalIndexResultSerializer();
+        DataInputDeserializer dataInputDeserializer = new 
DataInputDeserializer(data);
+        return globalIndexResultSerializer.deserialize(dataInputDeserializer);
+    }
+}
diff --git 
a/paimon-common/src/test/java/org/apache/paimon/utils/RoaringNavigableMap64Test.java
 
b/paimon-common/src/test/java/org/apache/paimon/utils/RoaringNavigableMap64Test.java
new file mode 100644
index 0000000000..ded850fb7d
--- /dev/null
+++ 
b/paimon-common/src/test/java/org/apache/paimon/utils/RoaringNavigableMap64Test.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.utils;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link RoaringNavigableMap64}. */
+public class RoaringNavigableMap64Test {
+
+    @Test
+    public void testAddRangeBasic() {
+        RoaringNavigableMap64 bitmap = new RoaringNavigableMap64();
+        bitmap.addRange(new Range(5, 10));
+
+        // Verify the range [5, 10] is added (inclusive on both ends)
+        assertThat(bitmap.getLongCardinality()).isEqualTo(6);
+        assertThat(bitmap.contains(4)).isFalse();
+        assertThat(bitmap.contains(5)).isTrue();
+        assertThat(bitmap.contains(7)).isTrue();
+        assertThat(bitmap.contains(10)).isTrue();
+        assertThat(bitmap.contains(11)).isFalse();
+    }
+
+    @Test
+    public void testAddRangeSingleElement() {
+        RoaringNavigableMap64 bitmap = new RoaringNavigableMap64();
+        bitmap.addRange(new Range(100, 100));
+
+        // A range where from == to should add exactly one element
+        assertThat(bitmap.getLongCardinality()).isEqualTo(1);
+        assertThat(bitmap.contains(99)).isFalse();
+        assertThat(bitmap.contains(100)).isTrue();
+        assertThat(bitmap.contains(101)).isFalse();
+    }
+
+    @Test
+    public void testAddRangeMultipleNonOverlapping() {
+        RoaringNavigableMap64 bitmap = new RoaringNavigableMap64();
+        bitmap.addRange(new Range(0, 5));
+        bitmap.addRange(new Range(10, 15));
+        bitmap.addRange(new Range(20, 25));
+
+        // Verify cardinality: 6 + 6 + 6 = 18
+        assertThat(bitmap.getLongCardinality()).isEqualTo(18);
+
+        // Verify gaps are not filled
+        assertThat(bitmap.contains(6)).isFalse();
+        assertThat(bitmap.contains(9)).isFalse();
+        assertThat(bitmap.contains(16)).isFalse();
+        assertThat(bitmap.contains(19)).isFalse();
+
+        // Verify ranges contain expected values
+        assertThat(bitmap.contains(0)).isTrue();
+        assertThat(bitmap.contains(5)).isTrue();
+        assertThat(bitmap.contains(10)).isTrue();
+        assertThat(bitmap.contains(15)).isTrue();
+        assertThat(bitmap.contains(20)).isTrue();
+        assertThat(bitmap.contains(25)).isTrue();
+
+        // Verify toRangeList reconstructs the ranges correctly
+        List<Range> ranges = bitmap.toRangeList();
+        assertThat(ranges).hasSize(3);
+        assertThat(ranges.get(0)).isEqualTo(new Range(0, 5));
+        assertThat(ranges.get(1)).isEqualTo(new Range(10, 15));
+        assertThat(ranges.get(2)).isEqualTo(new Range(20, 25));
+    }
+
+    @Test
+    public void testAddRangeLargeValues() {
+        RoaringNavigableMap64 bitmap = new RoaringNavigableMap64();
+        // Test with values beyond Integer.MAX_VALUE
+        long start = Integer.MAX_VALUE + 100L;
+        long end = Integer.MAX_VALUE + 200L;
+        bitmap.addRange(new Range(start, end));
+
+        assertThat(bitmap.getLongCardinality()).isEqualTo(101);
+        assertThat(bitmap.contains(start - 1)).isFalse();
+        assertThat(bitmap.contains(start)).isTrue();
+        assertThat(bitmap.contains(start + 50)).isTrue();
+        assertThat(bitmap.contains(end)).isTrue();
+        assertThat(bitmap.contains(end + 1)).isFalse();
+
+        // Verify iteration order
+        List<Long> values = new ArrayList<>();
+        bitmap.iterator().forEachRemaining(values::add);
+        assertThat(values).hasSize(101);
+        assertThat(values.get(0)).isEqualTo(start);
+        assertThat(values.get(100)).isEqualTo(end);
+    }
+}
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
 
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
index b8eed4e5b5..9d03f49379 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionBatchScan.java
@@ -55,6 +55,7 @@ public class DataEvolutionBatchScan implements DataTableScan {
 
     private Predicate filter;
     private List<Range> pushedRowRanges;
+    private GlobalIndexResult globalIndexResult;
 
     public DataEvolutionBatchScan(FileStoreTable wrapped, DataTableBatchScan 
batchScan) {
         this.table = wrapped;
@@ -148,6 +149,18 @@ public class DataEvolutionBatchScan implements 
DataTableScan {
     @Override
     public InnerTableScan withRowRanges(List<Range> rowRanges) {
         this.pushedRowRanges = rowRanges;
+        if (globalIndexResult != null) {
+            throw new IllegalStateException("");
+        }
+        return this;
+    }
+
+    // To enable other system computing index result by their own.
+    public InnerTableScan withGlobalIndexResult(GlobalIndexResult 
globalIndexResult) {
+        this.globalIndexResult = globalIndexResult;
+        if (pushedRowRanges != null) {
+            throw new IllegalStateException("");
+        }
         return this;
     }
 
@@ -160,6 +173,7 @@ public class DataEvolutionBatchScan implements 
DataTableScan {
     public Plan plan() {
         List<Range> rowRanges = this.pushedRowRanges;
         ScoreGetter scoreGetter = null;
+
         if (rowRanges == null) {
             Optional<GlobalIndexResult> indexResult = evalGlobalIndex();
             if (indexResult.isPresent()) {
@@ -180,6 +194,9 @@ public class DataEvolutionBatchScan implements 
DataTableScan {
     }
 
     private Optional<GlobalIndexResult> evalGlobalIndex() {
+        if (this.globalIndexResult != null) {
+            return Optional.of(globalIndexResult);
+        }
         if (filter == null) {
             return Optional.empty();
         }
@@ -237,7 +254,7 @@ public class DataEvolutionBatchScan implements 
DataTableScan {
 
             float[] scores = null;
             if (scoreGetter != null) {
-                int size = expected.stream().mapToInt(r -> (int) (r.to - 
r.from + 1)).sum();
+                int size = expected.stream().mapToInt(r -> (int) 
(r.count())).sum();
                 scores = new float[size];
 
                 int index = 0;
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionTableTest.java 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionTableTest.java
index 8845e22de9..3bbe513a62 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionTableTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/DataEvolutionTableTest.java
@@ -24,6 +24,7 @@ import org.apache.paimon.data.BinaryString;
 import org.apache.paimon.data.GenericRow;
 import org.apache.paimon.data.InternalRow;
 import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.globalindex.DataEvolutionBatchScan;
 import org.apache.paimon.globalindex.GlobalIndexFileReadWrite;
 import org.apache.paimon.globalindex.GlobalIndexResult;
 import org.apache.paimon.globalindex.GlobalIndexScanBuilder;
@@ -852,12 +853,13 @@ public class DataEvolutionTableTest extends TableTestBase 
{
                 .containsExactlyInAnyOrder(
                         new Range(200L, 200L), new Range(300L, 300L), new 
Range(400L, 400L));
 
-        ReadBuilder readBuilder = 
table.newReadBuilder().withRowRanges(rowIds.toRangeList());
+        DataEvolutionBatchScan scan = (DataEvolutionBatchScan) table.newScan();
+        RoaringNavigableMap64 finalRowIds = rowIds;
+        scan.withGlobalIndexResult(GlobalIndexResult.create(() -> 
finalRowIds));
 
         List<String> readF1 = new ArrayList<>();
-        readBuilder
-                .newRead()
-                .createReader(readBuilder.newScan().plan())
+        table.newRead()
+                .createReader(scan.plan())
                 .forEachRemaining(
                         row -> {
                             readF1.add(row.getString(1).toString());

Reply via email to