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 12b9facba0 [core] Centralize negative predicate complements in sorted
index readers (#9060)
12b9facba0 is described below
commit 12b9facba064600de251beca0d03950a39e918e3
Author: Jingsong Lee <[email protected]>
AuthorDate: Thu Aug 6 16:24:57 2026 +0800
[core] Centralize negative predicate complements in sorted index readers
(#9060)
---
.../paimon/globalindex/GlobalIndexReader.java | 5 --
.../apache/paimon/globalindex/GlobalIndexer.java | 7 ++
.../globalindex/OffsetGlobalIndexReader.java | 39 ----------
.../globalindex/SortedFileGlobalIndexReader.java | 56 +++++++++++----
.../globalindex/bitmap/BitmapGlobalIndexer.java | 3 +-
.../bitmap/LazyFilteredBitmapReader.java | 19 +----
.../globalindex/btree/BTreeGlobalIndexer.java | 2 +
.../globalindex/btree/LazyFilteredBTreeReader.java | 24 +------
.../globalindex/GlobalIndexEvaluatorTest.java | 82 +++++-----------------
.../bitmap/LazyFilteredBitmapIndexReaderTest.java | 72 +++++++++++++++++--
.../globalindex/btree/BTreeIndexReaderTest.java | 5 +-
.../globalindex/btree/BTreeThreadSafetyTest.java | 13 ++--
.../btree/LazyFilteredBTreeIndexReaderTest.java | 17 +++--
.../testfulltext/TestFullTextGlobalIndexer.java | 1 +
.../TestMultiFieldVectorGlobalIndexer.java | 5 +-
.../testvector/TestVectorGlobalIndexer.java | 1 +
.../DataEvolutionGlobalIndexScanner.java | 5 +-
.../pkfulltext/PrimaryKeyFullTextBucketSearch.java | 4 +-
.../index/pkvector/PkVectorAnnSegmentSearcher.java | 2 +
.../source/AbstractDataEvolutionVectorRead.java | 12 +++-
.../table/source/DataEvolutionFullTextRead.java | 6 +-
.../table/source/PrimaryKeyFullTextRead.java | 7 +-
.../table/source/PrimaryKeySortedIndexScan.java | 27 +++++--
.../index/pkfulltext/PkFullTextIndexFileTest.java | 1 +
.../PrimaryKeyFullTextBucketSearchTest.java | 13 ++--
.../index/pksorted/PkSortedIndexBuilderTest.java | 1 +
.../source/PrimaryKeySortedIndexBatchScanTest.java | 3 +-
.../source/PrimaryKeySortedIndexResultTest.java | 7 +-
.../source/PrimaryKeySortedIndexScanTest.java | 14 ++--
.../paimon/eslib/index/ESIndexGlobalIndexer.java | 1 +
.../index/ESIndexGlobalIndexerExecutorTest.java | 4 +-
.../eslib/index/ESIndexVectorMetricTest.java | 4 +-
.../FlinkDataEvolutionVectorReadTest.java | 1 +
.../index/NativeFullTextGlobalIndexer.java | 1 +
.../index/NativeFullTextGlobalIndexTest.java | 2 +-
.../index/NativePrimaryKeyFullTextIndexTest.java | 3 +-
.../lumina/index/LuminaVectorGlobalIndexer.java | 1 +
.../read/SparkDataEvolutionVectorReadTest.java | 1 +
.../vector/index/NativeVectorGlobalIndexer.java | 1 +
.../vector/index/NativeVectorGlobalIndexTest.java | 3 +-
40 files changed, 256 insertions(+), 219 deletions(-)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexReader.java
index 694d367aaa..b857fdc1a1 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexReader.java
@@ -36,11 +36,6 @@ import java.util.concurrent.CompletableFuture;
public interface GlobalIndexReader
extends
FunctionVisitor<CompletableFuture<Optional<GlobalIndexResult>>>, Closeable {
- /** Whether this reader can answer negative predicates by complementing a
known row range. */
- default boolean supportsRangeComplement() {
- return false;
- }
-
@Override
default CompletableFuture<Optional<GlobalIndexResult>> visitIsNaN(FieldRef
fieldRef) {
return CompletableFuture.completedFuture(Optional.empty());
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexer.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexer.java
index 5eadf0597f..eade369f7b 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexer.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/GlobalIndexer.java
@@ -32,9 +32,16 @@ public interface GlobalIndexer {
GlobalIndexWriter createWriter(GlobalIndexFileWriter fileWriter) throws
IOException;
+ /**
+ * Creates a reader whose relative row IDs cover {@code [0,
totalRowCount)}.
+ *
+ * <p>The complete row count lets an index implementation answer negative
predicates by
+ * complement, including for an empty shard.
+ */
GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor);
static GlobalIndexer create(String type, DataField indexField, Options
options) {
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/OffsetGlobalIndexReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/OffsetGlobalIndexReader.java
index 064893bf2e..23d38d3a94 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/OffsetGlobalIndexReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/OffsetGlobalIndexReader.java
@@ -23,7 +23,6 @@ import org.apache.paimon.predicate.FieldRef;
import org.apache.paimon.predicate.FullTextSearch;
import org.apache.paimon.predicate.TopN;
import org.apache.paimon.predicate.VectorSearch;
-import org.apache.paimon.utils.Range;
import java.io.IOException;
import java.util.ArrayList;
@@ -49,9 +48,6 @@ public class OffsetGlobalIndexReader implements
GlobalIndexReader {
@Override
public CompletableFuture<Optional<GlobalIndexResult>>
visitIsNotNull(FieldRef fieldRef) {
- if (wrapped.supportsRangeComplement()) {
- return complement(wrapped.visitIsNull(fieldRef));
- }
return wrapped.visitIsNotNull(fieldRef).thenApply(this::applyOffset);
}
@@ -99,12 +95,6 @@ public class OffsetGlobalIndexReader implements
GlobalIndexReader {
@Override
public CompletableFuture<Optional<GlobalIndexResult>> visitNotEqual(
FieldRef fieldRef, Object literal) {
- if (literal == null) {
- return
CompletableFuture.completedFuture(Optional.of(GlobalIndexResult.createEmpty()));
- }
- if (wrapped.supportsRangeComplement()) {
- return complement(wrapped.visitIsNull(fieldRef),
wrapped.visitEqual(fieldRef, literal));
- }
return wrapped.visitNotEqual(fieldRef,
literal).thenApply(this::applyOffset);
}
@@ -135,15 +125,6 @@ public class OffsetGlobalIndexReader implements
GlobalIndexReader {
@Override
public CompletableFuture<Optional<GlobalIndexResult>> visitNotIn(
FieldRef fieldRef, List<Object> literals) {
- for (Object literal : literals) {
- if (literal == null) {
- return CompletableFuture.completedFuture(
- Optional.of(GlobalIndexResult.createEmpty()));
- }
- }
- if (wrapped.supportsRangeComplement()) {
- return complement(wrapped.visitIsNull(fieldRef),
wrapped.visitIn(fieldRef, literals));
- }
return wrapped.visitNotIn(fieldRef,
literals).thenApply(this::applyOffset);
}
@@ -197,26 +178,6 @@ public class OffsetGlobalIndexReader implements
GlobalIndexReader {
return result.map(r -> r.offset(offset));
}
- @SafeVarargs
- private final CompletableFuture<Optional<GlobalIndexResult>> complement(
- CompletableFuture<Optional<GlobalIndexResult>>... excludeFutures) {
- return CompletableFuture.allOf(excludeFutures)
- .thenApply(
- ignored -> {
- GlobalIndexResult result =
- GlobalIndexResult.fromRange(new
Range(offset, to));
- for
(CompletableFuture<Optional<GlobalIndexResult>> future :
- excludeFutures) {
- Optional<GlobalIndexResult> excluded =
future.join();
- if (!excluded.isPresent()) {
- return Optional.empty();
- }
- result =
result.andNot(excluded.get().offset(offset));
- }
- return Optional.of(result);
- });
- }
-
@Override
public void close() throws IOException {
wrapped.close();
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/SortedFileGlobalIndexReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/SortedFileGlobalIndexReader.java
index f16c2036fe..814ec92414 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/SortedFileGlobalIndexReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/SortedFileGlobalIndexReader.java
@@ -29,6 +29,7 @@ import org.apache.paimon.predicate.LikeOptimization;
import org.apache.paimon.predicate.StartsWith;
import org.apache.paimon.types.DataTypeFamily;
import org.apache.paimon.utils.Pair;
+import org.apache.paimon.utils.Range;
import org.apache.paimon.utils.RoaringNavigableMap64;
import java.io.Closeable;
@@ -53,22 +54,29 @@ public abstract class SortedFileGlobalIndexReader<R extends
Closeable>
private final long fallbackScanMaxSize;
private final Map<Path, R> readerCache;
private final ExecutorService executor;
+ private final long totalRowCount;
protected SortedFileGlobalIndexReader(
List<GlobalIndexIOMeta> files,
KeySerializer keySerializer,
long fallbackScanMaxSize,
+ long totalRowCount,
ExecutorService executor) {
+ if (totalRowCount < 0) {
+ throw new IllegalArgumentException(
+ "Total row count must be non-negative, but was " +
totalRowCount + ".");
+ }
this.fileSelector = new SortedFileMetaSelector(files, keySerializer);
this.files = new ArrayList<>(files);
this.fallbackScanMaxSize = fallbackScanMaxSize;
this.readerCache = new ConcurrentHashMap<>();
this.executor = executor;
+ this.totalRowCount = totalRowCount;
}
@Override
public CompletableFuture<Optional<GlobalIndexResult>>
visitIsNotNull(FieldRef fieldRef) {
- return visitParallel(() -> fileSelector.visitIsNotNull(fieldRef),
this::visitIsNotNull);
+ return complement(visitIsNull(fieldRef));
}
@Override
@@ -169,9 +177,10 @@ public abstract class SortedFileGlobalIndexReader<R
extends Closeable>
@Override
public CompletableFuture<Optional<GlobalIndexResult>> visitNotEqual(
FieldRef fieldRef, Object literal) {
- return visitParallel(
- () -> fileSelector.visitNotEqual(fieldRef, literal),
- reader -> visitNotEqual(reader, literal));
+ if (literal == null) {
+ return
CompletableFuture.completedFuture(Optional.of(GlobalIndexResult.createEmpty()));
+ }
+ return complement(visitIsNull(fieldRef), visitEqual(fieldRef,
literal));
}
@Override
@@ -215,9 +224,13 @@ public abstract class SortedFileGlobalIndexReader<R
extends Closeable>
@Override
public CompletableFuture<Optional<GlobalIndexResult>> visitNotIn(
FieldRef fieldRef, List<Object> literals) {
- return visitParallel(
- () -> fileSelector.visitNotIn(fieldRef, literals),
- reader -> visitNotIn(reader, literals));
+ for (Object literal : literals) {
+ if (literal == null) {
+ return CompletableFuture.completedFuture(
+ Optional.of(GlobalIndexResult.createEmpty()));
+ }
+ }
+ return complement(visitIsNull(fieldRef), visitIn(fieldRef, literals));
}
@Override
@@ -246,8 +259,6 @@ public abstract class SortedFileGlobalIndexReader<R extends
Closeable>
reader -> visitNotBetween(reader, from, to));
}
- protected abstract Optional<GlobalIndexResult> visitIsNotNull(R reader);
-
protected abstract Optional<GlobalIndexResult> visitIsNull(R reader);
protected abstract Optional<GlobalIndexResult> visitStartsWith(R reader,
Object literal);
@@ -260,8 +271,6 @@ public abstract class SortedFileGlobalIndexReader<R extends
Closeable>
protected abstract Optional<GlobalIndexResult> visitGreaterOrEqual(R
reader, Object literal);
- protected abstract Optional<GlobalIndexResult> visitNotEqual(R reader,
Object literal);
-
protected abstract Optional<GlobalIndexResult> visitLessOrEqual(R reader,
Object literal);
protected abstract Optional<GlobalIndexResult> visitEqual(R reader, Object
literal);
@@ -270,8 +279,6 @@ public abstract class SortedFileGlobalIndexReader<R extends
Closeable>
protected abstract Optional<GlobalIndexResult> visitIn(R reader,
List<Object> literals);
- protected abstract Optional<GlobalIndexResult> visitNotIn(R reader,
List<Object> literals);
-
protected abstract Optional<GlobalIndexResult> visitBetween(R reader,
Object from, Object to);
protected Optional<GlobalIndexResult> visitLike(R reader, FieldRef
fieldRef, Object literal) {
@@ -348,6 +355,29 @@ public abstract class SortedFileGlobalIndexReader<R
extends Closeable>
return CompletableFuture.completedFuture(Optional.empty());
}
+ @SafeVarargs
+ private final CompletableFuture<Optional<GlobalIndexResult>> complement(
+ CompletableFuture<Optional<GlobalIndexResult>>... excludeFutures) {
+ return CompletableFuture.allOf(excludeFutures)
+ .thenApply(
+ ignored -> {
+ GlobalIndexResult result =
+ totalRowCount == 0
+ ? GlobalIndexResult.createEmpty()
+ : GlobalIndexResult.fromRange(
+ new Range(0, totalRowCount
- 1));
+ for
(CompletableFuture<Optional<GlobalIndexResult>> future :
+ excludeFutures) {
+ Optional<GlobalIndexResult> excluded =
future.join();
+ if (!excluded.isPresent()) {
+ return Optional.empty();
+ }
+ result = result.andNot(excluded.get());
+ }
+ return Optional.of(result);
+ });
+ }
+
private CompletableFuture<Optional<GlobalIndexResult>> visitParallel(
Supplier<Optional<List<GlobalIndexIOMeta>>> selector,
Function<R, Optional<GlobalIndexResult>> visitor) {
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/BitmapGlobalIndexer.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/BitmapGlobalIndexer.java
index 6a97d70bcc..e2a5c978f6 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/BitmapGlobalIndexer.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/BitmapGlobalIndexer.java
@@ -70,8 +70,9 @@ public class BitmapGlobalIndexer implements GlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
return new LazyFilteredBitmapReader(
- fileReader, files, keySerializer, fallbackScanMaxSize,
executor);
+ fileReader, files, keySerializer, fallbackScanMaxSize,
totalRowCount, executor);
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapReader.java
index 69c083a9fa..e0e25e79cf 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapReader.java
@@ -42,17 +42,13 @@ public class LazyFilteredBitmapReader extends
SortedFileGlobalIndexReader<Bitmap
List<GlobalIndexIOMeta> files,
KeySerializer keySerializer,
long fallbackScanMaxSize,
+ long totalRowCount,
ExecutorService executor) {
- super(files, keySerializer, fallbackScanMaxSize, executor);
+ super(files, keySerializer, fallbackScanMaxSize, totalRowCount,
executor);
this.fileReader = fileReader;
this.keySerializer = keySerializer;
}
- @Override
- protected Optional<GlobalIndexResult> visitIsNotNull(BitmapIndexReader
reader) {
- return reader.visitIsNotNull();
- }
-
@Override
protected Optional<GlobalIndexResult> visitIsNull(BitmapIndexReader
reader) {
return reader.visitIsNull();
@@ -85,11 +81,6 @@ public class LazyFilteredBitmapReader extends
SortedFileGlobalIndexReader<Bitmap
return reader.visitGreaterOrEqual(literal);
}
- @Override
- protected Optional<GlobalIndexResult> visitNotEqual(BitmapIndexReader
reader, Object literal) {
- return reader.visitNotEqual(literal);
- }
-
@Override
protected Optional<GlobalIndexResult> visitLessOrEqual(
BitmapIndexReader reader, Object literal) {
@@ -112,12 +103,6 @@ public class LazyFilteredBitmapReader extends
SortedFileGlobalIndexReader<Bitmap
return reader.visitIn(literals);
}
- @Override
- protected Optional<GlobalIndexResult> visitNotIn(
- BitmapIndexReader reader, List<Object> literals) {
- return reader.visitNotIn(literals);
- }
-
@Override
protected Optional<GlobalIndexResult> visitBetween(
BitmapIndexReader reader, Object from, Object to) {
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/BTreeGlobalIndexer.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/BTreeGlobalIndexer.java
index 24be409605..07de8ff58c 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/BTreeGlobalIndexer.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/BTreeGlobalIndexer.java
@@ -98,6 +98,7 @@ public class BTreeGlobalIndexer implements GlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
return new LazyFilteredBTreeReader(
files,
@@ -105,6 +106,7 @@ public class BTreeGlobalIndexer implements GlobalIndexer {
fileReader,
cacheManager.get(),
fallbackScanMaxSize,
+ totalRowCount,
executor);
}
}
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeReader.java
index f97d7a0735..75595f1bd1 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeReader.java
@@ -51,23 +51,14 @@ public class LazyFilteredBTreeReader extends
SortedFileGlobalIndexReader<BTreeIn
GlobalIndexFileReader fileReader,
CacheManager cacheManager,
long fallbackScanMaxSize,
+ long totalRowCount,
ExecutorService executor) {
- super(files, keySerializer, fallbackScanMaxSize, executor);
+ super(files, keySerializer, fallbackScanMaxSize, totalRowCount,
executor);
this.cacheManager = cacheManager;
this.fileReader = fileReader;
this.keySerializer = keySerializer;
}
- @Override
- public boolean supportsRangeComplement() {
- return true;
- }
-
- @Override
- protected Optional<GlobalIndexResult> visitIsNotNull(BTreeIndexReader
reader) {
- return reader.visitIsNotNull();
- }
-
@Override
protected Optional<GlobalIndexResult> visitIsNull(BTreeIndexReader reader)
{
return reader.visitIsNull();
@@ -105,11 +96,6 @@ public class LazyFilteredBTreeReader extends
SortedFileGlobalIndexReader<BTreeIn
return reader.visitGreaterOrEqual(literal);
}
- @Override
- protected Optional<GlobalIndexResult> visitNotEqual(BTreeIndexReader
reader, Object literal) {
- return reader.visitNotEqual(literal);
- }
-
@Override
protected Optional<GlobalIndexResult> visitLessOrEqual(
BTreeIndexReader reader, Object literal) {
@@ -132,12 +118,6 @@ public class LazyFilteredBTreeReader extends
SortedFileGlobalIndexReader<BTreeIn
return reader.visitIn(literals);
}
- @Override
- protected Optional<GlobalIndexResult> visitNotIn(
- BTreeIndexReader reader, List<Object> literals) {
- return reader.visitNotIn(literals);
- }
-
@Override
protected Optional<GlobalIndexResult> visitBetween(
BTreeIndexReader reader, Object from, Object to) {
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexEvaluatorTest.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexEvaluatorTest.java
index a480ae35af..8b7d677ed3 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexEvaluatorTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/GlobalIndexEvaluatorTest.java
@@ -807,98 +807,45 @@ class GlobalIndexEvaluatorTest {
}
@Test
- void testOffsetRangeComplementForNegativePredicates() {
+ void testOffsetDelegatesNegativePredicates() {
FieldRef fieldRef = new FieldRef(0, "a", DataTypes.INT());
AtomicBoolean isNotNullVisited = new AtomicBoolean();
- AtomicBoolean notEqualVisited = new AtomicBoolean();
- AtomicBoolean notInVisited = new AtomicBoolean();
+ AtomicInteger notEqualVisits = new AtomicInteger();
+ AtomicInteger notInVisits = new AtomicInteger();
GlobalIndexReader delegate =
new StubGlobalIndexReader(null) {
- @Override
- public boolean supportsRangeComplement() {
- return true;
- }
-
- @Override
- public CompletableFuture<Optional<GlobalIndexResult>>
visitIsNull(
- FieldRef fieldRef) {
- return
CompletableFuture.completedFuture(Optional.of(resultOf(2, 4)));
- }
-
- @Override
- public CompletableFuture<Optional<GlobalIndexResult>>
visitEqual(
- FieldRef fieldRef, Object literal) {
- return
CompletableFuture.completedFuture(Optional.of(resultOf(1, 3)));
- }
-
- @Override
- public CompletableFuture<Optional<GlobalIndexResult>>
visitIn(
- FieldRef fieldRef, List<Object> literals) {
- return
CompletableFuture.completedFuture(Optional.of(resultOf(0, 5)));
- }
-
@Override
public CompletableFuture<Optional<GlobalIndexResult>>
visitIsNotNull(
FieldRef fieldRef) {
isNotNullVisited.set(true);
- return
CompletableFuture.completedFuture(Optional.of(resultOf(999)));
+ return
CompletableFuture.completedFuture(Optional.of(resultOf(0, 4)));
}
@Override
public CompletableFuture<Optional<GlobalIndexResult>>
visitNotEqual(
FieldRef fieldRef, Object literal) {
- notEqualVisited.set(true);
- return
CompletableFuture.completedFuture(Optional.of(resultOf(999)));
+ notEqualVisits.incrementAndGet();
+ return CompletableFuture.completedFuture(
+ Optional.of(literal == null ? resultOf() :
resultOf(1, 3)));
}
@Override
public CompletableFuture<Optional<GlobalIndexResult>>
visitNotIn(
FieldRef fieldRef, List<Object> literals) {
- notInVisited.set(true);
- return
CompletableFuture.completedFuture(Optional.of(resultOf(999)));
+ notInVisits.incrementAndGet();
+ return CompletableFuture.completedFuture(
+ Optional.of(literals.contains(null) ?
resultOf() : resultOf(2)));
}
};
GlobalIndexReader reader = new OffsetGlobalIndexReader(delegate, 10L,
15L);
assertBitmapContainsExactly(
- reader.visitIsNotNull(fieldRef).join().get().results(), 10L,
11L, 13L, 15L);
+ reader.visitIsNotNull(fieldRef).join().get().results(), 10L,
14L);
assertBitmapContainsExactly(
- reader.visitNotEqual(fieldRef, 5).join().get().results(), 10L,
15L);
+ reader.visitNotEqual(fieldRef, 5).join().get().results(), 11L,
13L);
assertBitmapContainsExactly(
- reader.visitNotIn(fieldRef, Arrays.asList(5,
6)).join().get().results(), 11L, 13L);
- assertThat(isNotNullVisited).isFalse();
- assertThat(notEqualVisited).isFalse();
- assertThat(notInVisited).isFalse();
- }
-
- @Test
- void testOffsetRangeComplementNullAndUnsupportedPredicates() {
- FieldRef fieldRef = new FieldRef(0, "a", DataTypes.INT());
- GlobalIndexReader unsupportedEqual =
- new StubGlobalIndexReader(null) {
- @Override
- public boolean supportsRangeComplement() {
- return true;
- }
-
- @Override
- public CompletableFuture<Optional<GlobalIndexResult>>
visitIsNull(
- FieldRef fieldRef) {
- return CompletableFuture.completedFuture(
- Optional.of(GlobalIndexResult.createEmpty()));
- }
-
- @Override
- public CompletableFuture<Optional<GlobalIndexResult>>
visitEqual(
- FieldRef fieldRef, Object literal) {
- return
CompletableFuture.completedFuture(Optional.empty());
- }
- };
-
- GlobalIndexReader reader = new
OffsetGlobalIndexReader(unsupportedEqual, 10L, 15L);
-
- assertThat(reader.visitNotEqual(fieldRef, 5).join()).isEmpty();
+ reader.visitNotIn(fieldRef, Arrays.asList(5,
6)).join().get().results(), 12L);
assertThat(reader.visitNotEqual(fieldRef,
null).join().get().results().isEmpty()).isTrue();
assertThat(
reader.visitNotIn(fieldRef, Arrays.asList(5, null))
@@ -907,6 +854,9 @@ class GlobalIndexEvaluatorTest {
.results()
.isEmpty())
.isTrue();
+ assertThat(isNotNullVisited).isTrue();
+ assertThat(notEqualVisits).hasValue(2);
+ assertThat(notInVisits).hasValue(2);
}
@Test
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapIndexReaderTest.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapIndexReaderTest.java
index bf0b36f667..a032a312ee 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapIndexReaderTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/bitmap/LazyFilteredBitmapIndexReaderTest.java
@@ -110,7 +110,10 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Collections.singletonList(meta),
newDirectExecutorService())) {
+ fileReader,
+ Collections.singletonList(meta),
+ 6,
+ newDirectExecutorService())) {
assertRows(reader.visitEqual(fieldRef, str("A")).join(), 0L, 5L);
assertRows(reader.visitEqual(fieldRef, null).join());
assertRows(reader.visitEqual(fieldRef, str("missing")).join());
@@ -137,6 +140,44 @@ public class LazyFilteredBitmapIndexReaderTest {
}
}
+ @Test
+ public void testTotalRowCountComplementAvoidsOpeningAllBitmapFiles()
throws Exception {
+ List<GlobalIndexIOMeta> written = new ArrayList<>();
+ written.add(writeData(Collections.singletonList(Pair.of(null, 0L))));
+ written.add(writeData(Collections.singletonList(Pair.of(str("A"),
1L))));
+ written.add(writeData(Collections.singletonList(Pair.of(str("M"),
2L))));
+ written.add(writeData(Collections.singletonList(Pair.of(str("Z"),
3L))));
+
+ CountingGlobalIndexFileReader countingReader = new
CountingGlobalIndexFileReader();
+ try (GlobalIndexReader reader =
+ globalIndexer.createReader(
+ countingReader, written, 4,
newDirectExecutorService())) {
+ assertRows(reader.visitNotEqual(fieldRef, null).join());
+ assertRows(reader.visitNotIn(fieldRef, Arrays.asList(str("M"),
null)).join());
+ assertThat(countingReader.openCount()).isZero();
+
+ assertRows(reader.visitNotEqual(fieldRef, str("M")).join(), 1L,
3L);
+ assertThat(countingReader.openCount()).isEqualTo(2);
+
+ assertRows(reader.visitNotIn(fieldRef, Arrays.asList(str("M"),
str("Z"))).join(), 1L);
+ assertThat(countingReader.openCount()).isEqualTo(3);
+
+ assertRows(reader.visitIsNotNull(fieldRef).join(), 1L, 2L, 3L);
+ assertThat(countingReader.openCount()).isEqualTo(3);
+ }
+ }
+
+ @Test
+ public void testComplementsEmptyRowDomain() throws Exception {
+ try (GlobalIndexReader reader =
+ globalIndexer.createReader(
+ fileReader, Collections.emptyList(), 0,
newDirectExecutorService())) {
+ assertRows(reader.visitIsNotNull(fieldRef).join());
+ assertRows(reader.visitNotEqual(fieldRef, str("A")).join());
+ assertRows(reader.visitNotIn(fieldRef,
Collections.singletonList(str("A"))).join());
+ }
+ }
+
@Test
public void testFlushesCompletedBitmapBeforeFinish() throws Exception {
AtomicReference<ByteArrayPositionOutputStream> output = new
AtomicReference<>();
@@ -222,7 +263,10 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
intIndexer.createReader(
- fileReader, Collections.singletonList(meta),
newDirectExecutorService())) {
+ fileReader,
+ Collections.singletonList(meta),
+ 2,
+ newDirectExecutorService())) {
assertRows(reader.visitEqual(intFieldRef, 0).join(), 1L);
}
}
@@ -240,7 +284,10 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Collections.singletonList(meta),
newDirectExecutorService())) {
+ fileReader,
+ Collections.singletonList(meta),
+ 5,
+ newDirectExecutorService())) {
assertRows(reader.visitEndsWith(fieldRef, str("ta")).join(), 1L,
3L);
assertRows(reader.visitContains(fieldRef, str("ph")).join(), 0L,
2L);
assertRows(reader.visitLike(fieldRef, str("%ha%")).join(), 0L, 2L);
@@ -283,6 +330,7 @@ public class LazyFilteredBitmapIndexReaderTest {
globalIndexer.createReader(
fileReader,
Collections.singletonList(compressed),
+ 300,
newDirectExecutorService())) {
assertRows(reader.visitEqual(fieldRef, str(prefix +
"00123")).join(), 123L);
assertRows(
@@ -313,7 +361,10 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Collections.singletonList(meta),
newDirectExecutorService())) {
+ fileReader,
+ Collections.singletonList(meta),
+ 2,
+ newDirectExecutorService())) {
assertThat(reader.visitEndsWith(fieldRef,
str("ta")).join()).isEmpty();
assertThat(reader.visitContains(fieldRef,
str("ph")).join()).isEmpty();
assertThat(reader.visitLike(fieldRef,
str("%ha%")).join()).isEmpty();
@@ -337,7 +388,7 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Arrays.asList(first, second),
newDirectExecutorService())) {
+ fileReader, Arrays.asList(first, second), 6,
newDirectExecutorService())) {
assertRows(reader.visitEqual(fieldRef, str("B")).join(), 1L, 3L);
assertRows(reader.visitNotEqual(fieldRef, str("A")).join(), 1L,
3L, 4L);
assertRows(
@@ -361,6 +412,7 @@ public class LazyFilteredBitmapIndexReaderTest {
globalIndexer.createReader(
countingFileReader,
Arrays.asList(first, second),
+ 4,
newDirectExecutorService())) {
assertRows(reader.visitEqual(fieldRef, str("Z")).join(), 3L);
@@ -395,7 +447,7 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Arrays.asList(first, second),
newDirectExecutorService())) {
+ fileReader, Arrays.asList(first, second), 4,
newDirectExecutorService())) {
assertRows(reader.visitGreaterOrEqual(fieldRef, str("Y")).join(),
2L, 3L);
assertThat(reader.visitContains(fieldRef,
str("Z")).join()).isEmpty();
}
@@ -420,7 +472,10 @@ public class LazyFilteredBitmapIndexReaderTest {
try (GlobalIndexReader reader =
globalIndexer.createReader(
- fileReader, Collections.singletonList(meta),
newDirectExecutorService())) {
+ fileReader,
+ Collections.singletonList(meta),
+ 6,
+ newDirectExecutorService())) {
assertRows(reader.visitStartsWith(fieldRef, str("tag-")).join(),
2L, 3L);
}
}
@@ -450,6 +505,7 @@ public class LazyFilteredBitmapIndexReaderTest {
globalIndexer.createReader(
countingFileReader,
Collections.singletonList(meta),
+ 250,
newDirectExecutorService())) {
assertRows(reader.visitStartsWith(fieldRef,
str("tag-match")).join(), 100L, 101L, 102L);
@@ -478,6 +534,7 @@ public class LazyFilteredBitmapIndexReaderTest {
globalIndexer.createReader(
countingFileReader,
Collections.singletonList(meta),
+ 100,
newDirectExecutorService())) {
assertRows(reader.visitEqual(fieldRef, str("tag-050")).join(),
50L);
@@ -499,6 +556,7 @@ public class LazyFilteredBitmapIndexReaderTest {
globalIndexer.createReader(
countingFileReader,
Collections.singletonList(meta),
+ 3,
newDirectExecutorService())) {
assertRows(reader.visitIsNull(fieldRef).join(), 2L);
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeIndexReaderTest.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeIndexReaderTest.java
index 21a9870a79..b6e5eed591 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeIndexReaderTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeIndexReaderTest.java
@@ -51,7 +51,10 @@ public class BTreeIndexReaderTest extends
AbstractIndexReaderTest {
protected GlobalIndexReader prepareDataAndCreateReader() throws Exception {
GlobalIndexIOMeta written = writeData(data);
return globalIndexer.createReader(
- fileReader, Collections.singletonList(written),
newDirectExecutorService());
+ fileReader,
+ Collections.singletonList(written),
+ dataNum,
+ newDirectExecutorService());
}
@TestTemplate
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeThreadSafetyTest.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeThreadSafetyTest.java
index 2bf888fe87..2f22974c43 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeThreadSafetyTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/BTreeThreadSafetyTest.java
@@ -130,7 +130,8 @@ public class BTreeThreadSafetyTest {
executor = Executors.newFixedThreadPool(2);
List<GlobalIndexIOMeta> metas = writeMultipleFiles();
- try (GlobalIndexReader reader = globalIndexer.createReader(fileReader,
metas, executor)) {
+ try (GlobalIndexReader reader =
+ globalIndexer.createReader(fileReader, metas, DATA_NUM,
executor)) {
FieldRef ref = new FieldRef(1, "id", new IntType());
Optional<GlobalIndexResult> result =
reader.visitIsNotNull(ref).get(10, TimeUnit.SECONDS);
@@ -144,7 +145,8 @@ public class BTreeThreadSafetyTest {
executor = Executors.newFixedThreadPool(8);
List<GlobalIndexIOMeta> metas = writeMultipleFiles();
- try (GlobalIndexReader reader = globalIndexer.createReader(fileReader,
metas, executor)) {
+ try (GlobalIndexReader reader =
+ globalIndexer.createReader(fileReader, metas, DATA_NUM,
executor)) {
FieldRef ref = new FieldRef(1, "id", new IntType());
int numThreads = 32;
CountDownLatch latch = new CountDownLatch(numThreads);
@@ -187,7 +189,8 @@ public class BTreeThreadSafetyTest {
executor = Executors.newFixedThreadPool(4);
List<GlobalIndexIOMeta> metas = writeMultipleFiles();
- try (GlobalIndexReader reader = globalIndexer.createReader(fileReader,
metas, executor)) {
+ try (GlobalIndexReader reader =
+ globalIndexer.createReader(fileReader, metas, DATA_NUM,
executor)) {
FieldRef ref = new FieldRef(1, "id", new IntType());
int numThreads = 24;
CountDownLatch latch = new CountDownLatch(numThreads);
@@ -274,7 +277,7 @@ public class BTreeThreadSafetyTest {
};
try (GlobalIndexReader reader =
- globalIndexer.createReader(countingFileReader, metas,
executor)) {
+ globalIndexer.createReader(countingFileReader, metas,
DATA_NUM, executor)) {
FieldRef ref = new FieldRef(1, "id", new IntType());
int numThreads = 32;
CountDownLatch latch = new CountDownLatch(numThreads);
@@ -326,7 +329,7 @@ public class BTreeThreadSafetyTest {
};
try (GlobalIndexReader reader =
- globalIndexer.createReader(trackingFileReader, metas,
executor)) {
+ globalIndexer.createReader(trackingFileReader, metas,
DATA_NUM, executor)) {
FieldRef ref = new FieldRef(1, "id", new IntType());
// Query for value 5 — should only need to open the first file
(keys 0-999)
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeIndexReaderTest.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeIndexReaderTest.java
index 1fd4c509e9..7828a60bba 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeIndexReaderTest.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/btree/LazyFilteredBTreeIndexReaderTest.java
@@ -76,7 +76,7 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
@Override
protected GlobalIndexReader prepareDataAndCreateReader() throws Exception {
List<GlobalIndexIOMeta> written = writeData();
- return globalIndexer.createReader(fileReader, written,
newDirectExecutorService());
+ return globalIndexer.createReader(fileReader, written, dataNum,
newDirectExecutorService());
}
private List<GlobalIndexIOMeta> writeData() throws Exception {
@@ -110,7 +110,8 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
FieldRef ref = new FieldRef(1, "testField", dataType);
try (GlobalIndexReader reader =
- globalIndexer.createReader(fileReader, written,
newDirectExecutorService())) {
+ globalIndexer.createReader(
+ fileReader, written, dataNum,
newDirectExecutorService())) {
GlobalIndexResult result =
reader.visitTopN(new TopN(ref, DESCENDING, NULLS_LAST,
limit)).join().get();
assertThat(result.results().getLongCardinality()).isEqualTo(limit);
@@ -146,7 +147,8 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
Object max = data.get(dataNum - 1).getKey();
try (GlobalIndexReader reader =
- globalIndexer.createReader(fileReader, written,
newDirectExecutorService())) {
+ globalIndexer.createReader(
+ fileReader, written, dataNum,
newDirectExecutorService())) {
assertThat(reader.visitBetween(ref, min, max).join()).isEmpty();
GlobalIndexResult result = reader.visitEqual(ref,
literal).join().get();
@@ -176,7 +178,8 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
Object secondFileMin = data.get(split).getKey();
try (GlobalIndexReader reader =
- globalIndexer.createReader(fileReader, written,
newDirectExecutorService())) {
+ globalIndexer.createReader(
+ fileReader, written, dataNum,
newDirectExecutorService())) {
assertThat(reader.visitBetween(ref, min, max).join()).isEmpty();
GlobalIndexResult result = reader.visitGreaterOrEqual(ref,
secondFileMin).join().get();
@@ -202,7 +205,7 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
try (GlobalIndexReader reader =
new OffsetGlobalIndexReader(
globalIndexer.createReader(
- countingReader, written,
newDirectExecutorService()),
+ countingReader, written, 4,
newDirectExecutorService()),
1000L,
1003L)) {
GlobalIndexResult result = reader.visitNotEqual(ref,
100).join().get();
@@ -324,7 +327,7 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
// Real multi-threaded executor for the reader's internal file-level
parallelism
ExecutorService readerExecutor = Executors.newFixedThreadPool(8);
try (GlobalIndexReader reader =
- stressIndexer.createReader(fileReader, written,
readerExecutor)) {
+ stressIndexer.createReader(fileReader, written, dataNum,
readerExecutor)) {
FieldRef ref = new FieldRef(1, "testField", dataType);
int concurrency = 16;
@@ -407,7 +410,7 @@ public class LazyFilteredBTreeIndexReaderTest extends
AbstractIndexReaderTest {
new SemaphoredDelegatingExecutor(baseExecutor, 2, false);
try (GlobalIndexReader reader =
- globalIndexer.createReader(fileReader, written,
semaphoredExecutor)) {
+ globalIndexer.createReader(fileReader, written, dataNum,
semaphoredExecutor)) {
FieldRef ref = new FieldRef(1, "testField", dataType);
Random random = new Random(42);
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testfulltext/TestFullTextGlobalIndexer.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testfulltext/TestFullTextGlobalIndexer.java
index a7fdc0d49d..ac8ec32a6a 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testfulltext/TestFullTextGlobalIndexer.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testfulltext/TestFullTextGlobalIndexer.java
@@ -58,6 +58,7 @@ public class TestFullTextGlobalIndexer implements
GlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
checkArgument(files.size() == 1, "Expected exactly one index file per
shard");
return new TestFullTextGlobalIndexReader(fileReader, files.get(0));
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestMultiFieldVectorGlobalIndexer.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestMultiFieldVectorGlobalIndexer.java
index e984dd03b2..b3570b0be2 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestMultiFieldVectorGlobalIndexer.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestMultiFieldVectorGlobalIndexer.java
@@ -81,6 +81,7 @@ class TestMultiFieldVectorGlobalIndexer implements
VectorGlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
List<GlobalIndexIOMeta> vectorFiles = new ArrayList<>();
List<GlobalIndexIOMeta> scalarFiles = new ArrayList<>();
@@ -92,8 +93,8 @@ class TestMultiFieldVectorGlobalIndexer implements
VectorGlobalIndexer {
checkArgument(
scalarFiles.size() == 1, "Expected one scalar companion file,
got: %s", files);
return new MultiColumnReader(
- vectorIndexer.createReader(fileReader, vectorFiles, executor),
- scalarIndexer.createReader(fileReader, scalarFiles, executor));
+ vectorIndexer.createReader(fileReader, vectorFiles,
totalRowCount, executor),
+ scalarIndexer.createReader(fileReader, scalarFiles,
totalRowCount, executor));
}
@Override
diff --git
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestVectorGlobalIndexer.java
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestVectorGlobalIndexer.java
index eb0365427a..a114189ebb 100644
---
a/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestVectorGlobalIndexer.java
+++
b/paimon-common/src/test/java/org/apache/paimon/globalindex/testvector/TestVectorGlobalIndexer.java
@@ -105,6 +105,7 @@ public class TestVectorGlobalIndexer implements
VectorGlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
checkArgument(files.size() == 1, "Expected exactly one index file per
shard");
return new TestVectorGlobalIndexReader(
diff --git
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionGlobalIndexScanner.java
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionGlobalIndexScanner.java
index 9d6acaedde..d391743785 100644
---
a/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionGlobalIndexScanner.java
+++
b/paimon-core/src/main/java/org/apache/paimon/globalindex/DataEvolutionGlobalIndexScanner.java
@@ -442,7 +442,10 @@ public class DataEvolutionGlobalIndexScanner implements
Closeable {
() ->
new OffsetGlobalIndexReader(
globalIndexer.createReader(
- indexFileReadWrite,
globalMetas, executor),
+ indexFileReadWrite,
+ globalMetas,
+ range.count(),
+ executor),
range.from,
range.to),
executor));
diff --git
a/paimon-core/src/main/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearch.java
b/paimon-core/src/main/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearch.java
index 31f95a8839..2bdebce47d 100644
---
a/paimon-core/src/main/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearch.java
+++
b/paimon-core/src/main/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearch.java
@@ -113,7 +113,7 @@ public class PrimaryKeyFullTextBucketSearch {
if (include != null && include.isEmpty()) {
continue;
}
- GlobalIndexReader reader = readerFactory.create(payload);
+ GlobalIndexReader reader = readerFactory.create(payload,
totalRowCount);
CompletableFuture<Optional<ScoredGlobalIndexResult>> future;
try {
FullTextSearch predicate = new FullTextSearch(column, query,
limit);
@@ -213,7 +213,7 @@ public class PrimaryKeyFullTextBucketSearch {
/** Creates one independently closeable reader for an immutable payload
archive. */
@FunctionalInterface
public interface ReaderFactory {
- GlobalIndexReader create(IndexFileMeta payload);
+ GlobalIndexReader create(IndexFileMeta payload, long totalRowCount);
}
private static class PayloadRequest {
diff --git
a/paimon-core/src/main/java/org/apache/paimon/index/pkvector/PkVectorAnnSegmentSearcher.java
b/paimon-core/src/main/java/org/apache/paimon/index/pkvector/PkVectorAnnSegmentSearcher.java
index 75274336a9..1aff314898 100644
---
a/paimon-core/src/main/java/org/apache/paimon/index/pkvector/PkVectorAnnSegmentSearcher.java
+++
b/paimon-core/src/main/java/org/apache/paimon/index/pkvector/PkVectorAnnSegmentSearcher.java
@@ -203,6 +203,7 @@ public class PkVectorAnnSegmentSearcher {
indexer.createReader(
meta -> fileIO.newInputStream(meta.filePath()),
Collections.singletonList(ioMeta),
+ segment.rowCount(),
executor);
try {
VectorSearch search = new VectorSearch(query, limit,
vectorField.name(), searchOptions);
@@ -299,6 +300,7 @@ public class PkVectorAnnSegmentSearcher {
indexer.createReader(
meta -> fileIO.newInputStream(meta.filePath()),
Collections.singletonList(ioMeta),
+ segment.rowCount(),
executor);
try {
BatchVectorSearch search =
diff --git
a/paimon-core/src/main/java/org/apache/paimon/table/source/AbstractDataEvolutionVectorRead.java
b/paimon-core/src/main/java/org/apache/paimon/table/source/AbstractDataEvolutionVectorRead.java
index b35a1eb45c..83ea140270 100644
---
a/paimon-core/src/main/java/org/apache/paimon/table/source/AbstractDataEvolutionVectorRead.java
+++
b/paimon-core/src/main/java/org/apache/paimon/table/source/AbstractDataEvolutionVectorRead.java
@@ -258,7 +258,11 @@ public abstract class AbstractDataEvolutionVectorRead
implements Serializable {
FileIO fileIO = table.fileIO();
GlobalIndexFileReader indexFileReader = m ->
fileIO.newInputStream(m.filePath());
GlobalIndexReader reader =
- globalIndexer.createReader(indexFileReader, indexIOMetaList,
executor);
+ globalIndexer.createReader(
+ indexFileReader,
+ indexIOMetaList,
+ rowRangeEnd - rowRangeStart + 1,
+ executor);
VectorSearch vectorSearch =
new VectorSearch(vector, searchLimit, vectorColumn.name(),
options)
.withIncludeRowIds(includeRowIds);
@@ -287,7 +291,11 @@ public abstract class AbstractDataEvolutionVectorRead
implements Serializable {
FileIO fileIO = table.fileIO();
GlobalIndexFileReader indexFileReader = m ->
fileIO.newInputStream(m.filePath());
GlobalIndexReader reader =
- globalIndexer.createReader(indexFileReader, indexIOMetaList,
executor);
+ globalIndexer.createReader(
+ indexFileReader,
+ indexIOMetaList,
+ rowRangeEnd - rowRangeStart + 1,
+ executor);
BatchVectorSearch batchVectorSearch =
new BatchVectorSearch(vectors, searchLimit,
vectorColumn.name(), options)
.withIncludeRowIds(includeRowIds);
diff --git
a/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionFullTextRead.java
b/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionFullTextRead.java
index 780155f837..40e492968c 100644
---
a/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionFullTextRead.java
+++
b/paimon-core/src/main/java/org/apache/paimon/table/source/DataEvolutionFullTextRead.java
@@ -254,7 +254,11 @@ public class DataEvolutionFullTextRead implements
FullTextRead {
meta.indexMeta()));
}
GlobalIndexReader reader =
- globalIndexer.createReader(indexFileReader, indexIOMetaList,
executor);
+ globalIndexer.createReader(
+ indexFileReader,
+ indexIOMetaList,
+ rowRangeEnd - rowRangeStart + 1,
+ executor);
FullTextSearch fullTextSearch =
new FullTextSearch(
textColumn.name(),
diff --git
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeyFullTextRead.java
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeyFullTextRead.java
index c514301be0..edc56a372f 100644
---
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeyFullTextRead.java
+++
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeyFullTextRead.java
@@ -189,7 +189,7 @@ public class PrimaryKeyFullTextRead implements FullTextRead
{
indexFileHandler.pkFullTextIndex(
split.dataSplit().partition(),
split.dataSplit().bucket());
return new PrimaryKeyFullTextBucketSearch(
- payload -> {
+ (payload, totalRowCount) -> {
GlobalIndexMeta meta =
checkNotNull(payload.globalIndexMeta());
GlobalIndexIOMeta ioMeta =
new GlobalIndexIOMeta(
@@ -198,7 +198,10 @@ public class PrimaryKeyFullTextRead implements
FullTextRead {
meta.indexMeta());
GlobalIndexReader reader =
indexer.createReader(
- archiveReader,
Collections.singletonList(ioMeta), executor);
+ archiveReader,
+ Collections.singletonList(ioMeta),
+ totalRowCount,
+ executor);
return reader;
});
}
diff --git
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
index adea4965ac..7bc04f5d6f 100644
---
a/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
+++
b/paimon-core/src/main/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScan.java
@@ -83,7 +83,10 @@ public final class PrimaryKeySortedIndexScan {
public interface ReaderFactory {
GlobalIndexReader create(
- FilePlan file, PrimaryKeyIndexDefinition definition,
List<IndexFileMeta> payloads);
+ FilePlan file,
+ PrimaryKeyIndexDefinition definition,
+ List<IndexFileMeta> payloads,
+ long totalRowCount);
}
static ReaderFactory readerFactory(
@@ -92,7 +95,7 @@ public final class PrimaryKeySortedIndexScan {
ExecutorService executor =
GlobalIndexReadThreadPool.getExecutorService(options.get(GLOBAL_INDEX_THREAD_NUM));
GlobalIndexFileReader fileReader = meta ->
fileIO.newInputStream(meta.filePath());
- return (file, definition, payloads) -> {
+ return (file, definition, payloads, totalRowCount) -> {
IndexPathFactory indexPathFactory =
pathFactories.get(file.sourceSplit().partition(),
file.sourceSplit().bucket());
List<GlobalIndexIOMeta> ioMetas = new ArrayList<>(payloads.size());
@@ -109,7 +112,7 @@ public final class PrimaryKeySortedIndexScan {
definition.indexType(),
rowType.getField(definition.fieldId()),
definition.options());
- return indexer.createReader(fileReader, ioMetas, executor);
+ return indexer.createReader(fileReader, ioMetas, totalRowCount,
executor);
};
}
@@ -257,15 +260,19 @@ public final class PrimaryKeySortedIndexScan {
}
SharedGlobalIndexReader reader =
sharedReaders.get(group.get());
if (reader == null) {
+ PkSortedIndexGroup indexGroup =
group.get();
+ long totalRowCount =
+
totalRowCount(indexGroup.sourceFiles());
reader =
new SharedGlobalIndexReader(
-
group.get().sourceFiles(),
+
indexGroup.sourceFiles(),
() ->
readerFactory.create(
file,
definition,
-
group.get().payloads()));
- sharedReaders.put(group.get(), reader);
+
indexGroup.payloads(),
+
totalRowCount));
+ sharedReaders.put(indexGroup, reader);
}
return Collections.singletonList(
fileLocalReader(file, group.get(),
reader));
@@ -312,6 +319,14 @@ public final class PrimaryKeySortedIndexScan {
return new FileLocalGlobalIndexReader(reader, sourceIndex);
}
+ private static long totalRowCount(List<PrimaryKeyIndexSourceFile>
sourceFiles) {
+ long totalRowCount = 0;
+ for (PrimaryKeyIndexSourceFile sourceFile : sourceFiles) {
+ totalRowCount = Math.addExact(totalRowCount,
sourceFile.rowCount());
+ }
+ return totalRowCount;
+ }
+
private static void rethrowIfInterrupted(RuntimeException exception) {
if (Thread.currentThread().isInterrupted()) {
throw exception;
diff --git
a/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PkFullTextIndexFileTest.java
b/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PkFullTextIndexFileTest.java
index ffbfab5ff6..59583e45e1 100644
---
a/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PkFullTextIndexFileTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PkFullTextIndexFileTest.java
@@ -273,6 +273,7 @@ class PkFullTextIndexFileTest {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
throw new UnsupportedOperationException();
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearchTest.java
b/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearchTest.java
index d5e148341e..231343cac5 100644
---
a/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearchTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/index/pkfulltext/PrimaryKeyFullTextBucketSearchTest.java
@@ -71,7 +71,7 @@ class PrimaryKeyFullTextBucketSearchTest {
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- payload -> {
+ (payload, ignoredTotalRowCount) -> {
String source =
PrimaryKeyIndexSourceMeta.fromIndexFile(payload)
.sourceFile()
@@ -101,7 +101,7 @@ class PrimaryKeyFullTextBucketSearchTest {
AtomicInteger closes = new AtomicInteger();
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- payload -> reader(scores(0, 1F, 2, 10F), closes));
+ (payload, ignoredTotalRowCount) -> reader(scores(0,
1F, 2, 10F), closes));
PrimaryKeyFullTextSearchSplit split =
new PrimaryKeyFullTextSearchSplit(
dataSplit(Collections.singletonList(dataFile("a"))),
@@ -125,7 +125,10 @@ class PrimaryKeyFullTextBucketSearchTest {
AtomicInteger closes = new AtomicInteger();
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- ignored -> reader(scores(0, 10F, 3, 9F, 4, 8F, 5, 7F),
closes));
+ (ignored, totalRowCount) -> {
+ assertThat(totalRowCount).isEqualTo(6);
+ return reader(scores(0, 10F, 3, 9F, 4, 8F, 5, 7F),
closes);
+ });
PrimaryKeyFullTextSearchSplit split =
new PrimaryKeyFullTextSearchSplit(
dataSplit(Arrays.asList(dataFile("a"), dataFile("b"))),
@@ -158,7 +161,7 @@ class PrimaryKeyFullTextBucketSearchTest {
AtomicInteger closes = new AtomicInteger();
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- ignored -> reader(Collections.emptyMap(), closes));
+ (ignored, ignoredTotalRowCount) ->
reader(Collections.emptyMap(), closes));
PrimaryKeyFullTextSearchSplit split =
new PrimaryKeyFullTextSearchSplit(
dataSplit(Collections.singletonList(dataFile("large",
rowCount))),
@@ -182,7 +185,7 @@ class PrimaryKeyFullTextBucketSearchTest {
AtomicInteger closes = new AtomicInteger();
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- payload ->
+ (payload, ignoredTotalRowCount) ->
new FullTextOnlyReader() {
@Override
public
CompletableFuture<Optional<ScoredGlobalIndexResult>>
diff --git
a/paimon-core/src/test/java/org/apache/paimon/index/pksorted/PkSortedIndexBuilderTest.java
b/paimon-core/src/test/java/org/apache/paimon/index/pksorted/PkSortedIndexBuilderTest.java
index db2d6d0b94..a57363e4b1 100644
---
a/paimon-core/src/test/java/org/apache/paimon/index/pksorted/PkSortedIndexBuilderTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/index/pksorted/PkSortedIndexBuilderTest.java
@@ -238,6 +238,7 @@ class PkSortedIndexBuilderTest {
.createReader(
new GlobalIndexFileReadWrite(fileIO,
pathFactory),
ioMetas,
+ payload.rowCount(),
executor)) {
FieldRef fieldRef = new FieldRef(7, "indexed", DataTypes.INT());
GlobalIndexResult result =
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexBatchScanTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexBatchScanTest.java
index f4d8243a3c..bdb286c508 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexBatchScanTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexBatchScanTest.java
@@ -223,7 +223,8 @@ class PrimaryKeySortedIndexBatchScanTest {
table,
snapshotReader,
mock(TableQueryAuth.class),
- (ignoredFile, ignoredDefinition, ignoredPayloads) ->
reader);
+ (ignoredFile, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
+ reader);
scan.withFilter(predicate);
return new ScanFixture(dataFile, scan);
}
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexResultTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexResultTest.java
index 34429e545c..0aa9e0ebc9 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexResultTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexResultTest.java
@@ -95,7 +95,7 @@ class PrimaryKeySortedIndexResultTest {
rowType,
predicate,
Collections.singletonList(definition),
- (file, ignoredDefinition, ignoredPayloads) -> {
+ (file, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) -> {
if (file.dataFile().fileName().equals("indexed")) {
return reader(1, 2, 4);
} else if
(file.dataFile().fileName().equals("empty")) {
@@ -152,7 +152,7 @@ class PrimaryKeySortedIndexResultTest {
rowType,
predicate,
Collections.singletonList(definition),
- (file, ignoredDefinition, ignoredPayloads) ->
+ (file, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
file.dataFile().fileName().equals("first") ?
reader(1) : reader(2));
PrimaryKeySortedIndexResult result = new
PrimaryKeySortedIndexResult(evaluated);
@@ -195,7 +195,8 @@ class PrimaryKeySortedIndexResultTest {
rowType,
predicate,
Collections.singletonList(definition),
- (ignoredFile, ignoredDefinition, ignoredPayloads) ->
reader(positions));
+ (ignoredFile, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
+ reader(positions));
PrimaryKeySortedIndexResult result = new
PrimaryKeySortedIndexResult(evaluated);
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
index af44371136..c704589af7 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/source/PrimaryKeySortedIndexScanTest.java
@@ -191,7 +191,7 @@ class PrimaryKeySortedIndexScanTest {
rowType,
predicate,
Collections.singletonList(definition),
- (ignoredFile, ignoredDefinition, payloads) -> {
+ (ignoredFile, ignoredDefinition, payloads,
ignoredTotalRowCount) -> {
readersCreated.incrementAndGet();
return reader;
});
@@ -248,9 +248,10 @@ class PrimaryKeySortedIndexScanTest {
rowType,
predicate,
Collections.singletonList(definition),
- (ignoredFile, ignoredDefinition, payloads) -> {
+ (ignoredFile, ignoredDefinition, payloads,
totalRowCount) -> {
readersCreated.incrementAndGet();
assertThat(payloads).containsExactly(mergedPayload);
+ assertThat(totalRowCount).isEqualTo(5);
return reader;
});
PrimaryKeySortedIndexResult result = new
PrimaryKeySortedIndexResult(evaluated);
@@ -297,14 +298,16 @@ class PrimaryKeySortedIndexScanTest {
rowType,
PredicateBuilder.and(builder.equal(0, 42),
builder.equal(1, 99)),
Collections.singletonList(definition),
- (ignoredFile, ignoredDefinition, ignoredPayloads) ->
reader);
+ (ignoredFile, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
+ reader);
PrimaryKeySortedIndexScan.EvaluatedPlan orResult =
PrimaryKeySortedIndexScan.evaluate(
plan,
rowType,
PredicateBuilder.or(builder.equal(0, 42),
builder.equal(1, 99)),
Collections.singletonList(definition),
- (ignoredFile, ignoredDefinition, ignoredPayloads) ->
reader);
+ (ignoredFile, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
+ reader);
assertThat(andResult.files().get(0).result()).isPresent();
assertThat(andResult.files().get(0).result().get().results()).containsExactly(2L);
@@ -346,7 +349,8 @@ class PrimaryKeySortedIndexScanTest {
rowType,
predicate,
Collections.singletonList(definition),
- (file, ignoredDefinition, ignoredPayloads) ->
failedReader);
+ (file, ignoredDefinition, ignoredPayloads,
ignoredTotalRowCount) ->
+ failedReader);
assertThat(evaluated.files()).hasSize(2);
assertThat(evaluated.files().get(0).result()).isEmpty();
diff --git
a/paimon-eslib/src/main/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexer.java
b/paimon-eslib/src/main/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexer.java
index 0167e24066..3ae8620624 100644
---
a/paimon-eslib/src/main/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexer.java
+++
b/paimon-eslib/src/main/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexer.java
@@ -61,6 +61,7 @@ public class ESIndexGlobalIndexer implements
VectorGlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
ESIndexGlobalIndexReader reader =
new ESIndexGlobalIndexReader(fileReader, files, fields,
indexOptions, executor);
diff --git
a/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexerExecutorTest.java
b/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexerExecutorTest.java
index 952ea8b093..c693225c3a 100644
---
a/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexerExecutorTest.java
+++
b/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexGlobalIndexerExecutorTest.java
@@ -66,7 +66,7 @@ class ESIndexGlobalIndexerExecutorTest {
ExecutorService caller = Executors.newSingleThreadExecutor();
try {
ESIndexGlobalIndexer indexer = new ESIndexGlobalIndexer(FIELDS,
new Options());
- GlobalIndexReader reader = indexer.createReader(meta -> null,
oneFile(), caller);
+ GlobalIndexReader reader = indexer.createReader(meta -> null,
oneFile(), 1, caller);
assertSame(
caller,
((ESIndexGlobalIndexReader) reader).queryExecutor(),
@@ -80,7 +80,7 @@ class ESIndexGlobalIndexerExecutorTest {
void inlineValidationFailuresCompleteTheReturnedFutureExceptionally()
throws Exception {
ESIndexGlobalIndexer indexer = new ESIndexGlobalIndexer(FIELDS, new
Options());
ESIndexGlobalIndexReader reader =
- (ESIndexGlobalIndexReader) indexer.createReader(meta -> null,
oneFile(), null);
+ (ESIndexGlobalIndexReader) indexer.createReader(meta -> null,
oneFile(), 1, null);
try {
CompletableFuture<?> future =
reader.visitFullTextSearch(new FullTextSearch("k",
"{not-json", 1));
diff --git
a/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexVectorMetricTest.java
b/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexVectorMetricTest.java
index fceab62411..505de4d53e 100644
---
a/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexVectorMetricTest.java
+++
b/paimon-eslib/src/test/java/org/apache/paimon/eslib/index/ESIndexVectorMetricTest.java
@@ -68,6 +68,7 @@ class ESIndexVectorMetricTest {
indexer.createReader(
meta -> null,
List.of(vectorFile(tempDir, "persisted-l2",
"euclidean")),
+ 1,
null);
try {
assertThat(((ESIndexGlobalIndexReader)
reader).primaryVectorMetric()).isEqualTo("l2");
@@ -82,13 +83,14 @@ class ESIndexVectorMetricTest {
ESIndexGlobalIndexer indexer = indexer("cosine");
GlobalIndexReader first =
indexer.createReader(
- meta -> null, List.of(vectorFile(tempDir, "first",
"euclidean")), null);
+ meta -> null, List.of(vectorFile(tempDir, "first",
"euclidean")), 1, null);
try {
assertThatThrownBy(
() ->
indexer.createReader(
meta -> null,
List.of(vectorFile(tempDir,
"second", "cosine")),
+ 1,
null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("different vector metrics")
diff --git
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/vectorsearch/FlinkDataEvolutionVectorReadTest.java
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/vectorsearch/FlinkDataEvolutionVectorReadTest.java
index 9bd45a7776..a39e777168 100644
---
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/vectorsearch/FlinkDataEvolutionVectorReadTest.java
+++
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/vectorsearch/FlinkDataEvolutionVectorReadTest.java
@@ -543,6 +543,7 @@ public class FlinkDataEvolutionVectorReadTest {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
throw new UnsupportedOperationException();
}
diff --git
a/paimon-full-text/src/main/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexer.java
b/paimon-full-text/src/main/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexer.java
index 564cafa809..c8c0bb3867 100644
---
a/paimon-full-text/src/main/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexer.java
+++
b/paimon-full-text/src/main/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexer.java
@@ -50,6 +50,7 @@ public class NativeFullTextGlobalIndexer implements
GlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
return new NativeFullTextGlobalIndexReader(fileReader, files,
executor);
}
diff --git
a/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexTest.java
b/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexTest.java
index a129aec198..e5d8f482ca 100644
---
a/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexTest.java
+++
b/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativeFullTextGlobalIndexTest.java
@@ -402,7 +402,7 @@ public class NativeFullTextGlobalIndexTest {
try (NativeFullTextGlobalIndexReader reader =
(NativeFullTextGlobalIndexReader)
- indexer.createReader(fileReader, metas,
newDirectExecutorService())) {
+ indexer.createReader(fileReader, metas, 1,
newDirectExecutorService())) {
FullTextSearch search = new FullTextSearch("text",
matchQuery("indexer"), 10);
Optional<ScoredGlobalIndexResult> searchResult =
reader.visitFullTextSearch(search).join();
diff --git
a/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativePrimaryKeyFullTextIndexTest.java
b/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativePrimaryKeyFullTextIndexTest.java
index ce1100f590..a9ca34dc42 100644
---
a/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativePrimaryKeyFullTextIndexTest.java
+++
b/paimon-full-text/src/test/java/org/apache/paimon/fulltext/index/NativePrimaryKeyFullTextIndexTest.java
@@ -131,10 +131,11 @@ class NativePrimaryKeyFullTextIndexTest {
GlobalIndexer indexer = GlobalIndexer.create("full-text", TEXT_FIELD,
options);
PrimaryKeyFullTextBucketSearch search =
new PrimaryKeyFullTextBucketSearch(
- payload ->
+ (payload, totalRowCount) ->
indexer.createReader(
fileReader(),
Collections.singletonList(toIOMeta(payload)),
+ totalRowCount,
newDirectExecutorService()));
List<List<PrimaryKeySearchPosition>> rankings =
diff --git
a/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorGlobalIndexer.java
b/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorGlobalIndexer.java
index 69b73a6bce..87ca7d4b47 100644
---
a/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorGlobalIndexer.java
+++
b/paimon-lumina/src/main/java/org/apache/paimon/lumina/index/LuminaVectorGlobalIndexer.java
@@ -50,6 +50,7 @@ public class LuminaVectorGlobalIndexer implements
VectorGlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
return new LuminaVectorGlobalIndexReader(fileReader, files, fieldType,
options, executor);
}
diff --git
a/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/read/SparkDataEvolutionVectorReadTest.java
b/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/read/SparkDataEvolutionVectorReadTest.java
index 2479118c32..dd13cd365b 100644
---
a/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/read/SparkDataEvolutionVectorReadTest.java
+++
b/paimon-spark/paimon-spark-common/src/test/java/org/apache/paimon/spark/read/SparkDataEvolutionVectorReadTest.java
@@ -440,6 +440,7 @@ public class SparkDataEvolutionVectorReadTest {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
throw new UnsupportedOperationException();
}
diff --git
a/paimon-vector/src/main/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexer.java
b/paimon-vector/src/main/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexer.java
index 37e20e0af5..2498e8d31b 100644
---
a/paimon-vector/src/main/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexer.java
+++
b/paimon-vector/src/main/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexer.java
@@ -79,6 +79,7 @@ public class NativeVectorGlobalIndexer implements
VectorGlobalIndexer {
public GlobalIndexReader createReader(
GlobalIndexFileReader fileReader,
List<GlobalIndexIOMeta> files,
+ long totalRowCount,
ExecutorService executor) {
return new NativeVectorGlobalIndexReader(fileReader, files, fieldType,
executor);
}
diff --git
a/paimon-vector/src/test/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexTest.java
b/paimon-vector/src/test/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexTest.java
index 4995f3e886..eb7750915a 100644
---
a/paimon-vector/src/test/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexTest.java
+++
b/paimon-vector/src/test/java/org/apache/paimon/vector/index/NativeVectorGlobalIndexTest.java
@@ -508,7 +508,8 @@ public class NativeVectorGlobalIndexTest {
GlobalIndexFileReader fileReader = createFileReader(indexPath);
try (NativeVectorGlobalIndexReader reader =
- (NativeVectorGlobalIndexReader)
indexer.createReader(fileReader, metas, executor)) {
+ (NativeVectorGlobalIndexReader)
+ indexer.createReader(fileReader, metas,
vectors.length, executor)) {
VectorSearch vectorSearch = new VectorSearch(vectors[0], 2,
fieldName);
ScoredGlobalIndexResult result =
reader.visitVectorSearch(vectorSearch).join().get();
assertThat(result.results().getLongCardinality()).isEqualTo(2);