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 67435d2a40 [core] Fix unsupported predicate fallback for global
indexes (#8790)
67435d2a40 is described below
commit 67435d2a4079f194949e62983d319597bd969960
Author: QuakeWang <[email protected]>
AuthorDate: Wed Jul 22 14:45:07 2026 +0800
[core] Fix unsupported predicate fallback for global indexes (#8790)
---
.../globalindex/ConstantGlobalIndexReader.java | 11 ++++
.../paimon/globalindex/GlobalIndexReader.java | 18 ++++++
.../globalindex/OffsetGlobalIndexReader.java | 6 ++
.../paimon/globalindex/UnionGlobalIndexReader.java | 6 ++
.../globalindex/GlobalIndexEvaluatorTest.java | 69 ++++++++++++++++++++++
5 files changed, 110 insertions(+)
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/ConstantGlobalIndexReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/ConstantGlobalIndexReader.java
index fe610f9668..d30c758fd6 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/ConstantGlobalIndexReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/ConstantGlobalIndexReader.java
@@ -49,6 +49,11 @@ public class ConstantGlobalIndexReader implements
GlobalIndexReader {
return result;
}
+ @Override
+ public CompletableFuture<Optional<GlobalIndexResult>> visitIsNaN(FieldRef
fieldRef) {
+ return result;
+ }
+
@Override
public CompletableFuture<Optional<GlobalIndexResult>> visitStartsWith(
FieldRef fieldRef, Object literal) {
@@ -127,6 +132,12 @@ public class ConstantGlobalIndexReader implements
GlobalIndexReader {
return result;
}
+ @Override
+ public CompletableFuture<Optional<GlobalIndexResult>> visitNotBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return result;
+ }
+
@Override
public void close() {}
}
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 5951d40726..807ecb8aa0 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
@@ -19,6 +19,7 @@
package org.apache.paimon.globalindex;
import org.apache.paimon.predicate.BatchVectorSearch;
+import org.apache.paimon.predicate.FieldRef;
import org.apache.paimon.predicate.FullTextSearch;
import org.apache.paimon.predicate.FunctionVisitor;
import org.apache.paimon.predicate.LeafPredicate;
@@ -34,6 +35,23 @@ import java.util.concurrent.CompletableFuture;
public interface GlobalIndexReader
extends
FunctionVisitor<CompletableFuture<Optional<GlobalIndexResult>>>, Closeable {
+ @Override
+ default CompletableFuture<Optional<GlobalIndexResult>> visitIsNaN(FieldRef
fieldRef) {
+ return CompletableFuture.completedFuture(Optional.empty());
+ }
+
+ @Override
+ default CompletableFuture<Optional<GlobalIndexResult>> visitBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return CompletableFuture.completedFuture(Optional.empty());
+ }
+
+ @Override
+ default CompletableFuture<Optional<GlobalIndexResult>> visitNotBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return CompletableFuture.completedFuture(Optional.empty());
+ }
+
@Override
default CompletableFuture<Optional<GlobalIndexResult>> visitAnd(
List<CompletableFuture<Optional<GlobalIndexResult>>> children) {
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 646e1f6ca2..7b513a2c39 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
@@ -133,6 +133,12 @@ public class OffsetGlobalIndexReader implements
GlobalIndexReader {
return wrapped.visitBetween(fieldRef, from,
to).thenApply(this::applyOffset);
}
+ @Override
+ public CompletableFuture<Optional<GlobalIndexResult>> visitNotBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return wrapped.visitNotBetween(fieldRef, from,
to).thenApply(this::applyOffset);
+ }
+
@Override
public CompletableFuture<Optional<ScoredGlobalIndexResult>>
visitVectorSearch(
VectorSearch vectorSearch) {
diff --git
a/paimon-common/src/main/java/org/apache/paimon/globalindex/UnionGlobalIndexReader.java
b/paimon-common/src/main/java/org/apache/paimon/globalindex/UnionGlobalIndexReader.java
index 57eb372591..c901d4905c 100644
---
a/paimon-common/src/main/java/org/apache/paimon/globalindex/UnionGlobalIndexReader.java
+++
b/paimon-common/src/main/java/org/apache/paimon/globalindex/UnionGlobalIndexReader.java
@@ -136,6 +136,12 @@ public class UnionGlobalIndexReader implements
GlobalIndexReader {
return unionAsync(reader -> reader.visitBetween(fieldRef, from, to));
}
+ @Override
+ public CompletableFuture<Optional<GlobalIndexResult>> visitNotBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return unionAsync(reader -> reader.visitNotBetween(fieldRef, from,
to));
+ }
+
@Override
public CompletableFuture<Optional<ScoredGlobalIndexResult>>
visitVectorSearch(
VectorSearch vectorSearch) {
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 b2e75a4b6e..dcd36c8eaa 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
@@ -643,6 +643,75 @@ class GlobalIndexEvaluatorTest {
evaluator.close();
}
+ @Test
+ void testUnsupportedIsNaNFallsBack() {
+ RowType rowType =
+ new RowType(Collections.singletonList(new DataField(0, "a",
DataTypes.DOUBLE())));
+ GlobalIndexEvaluator evaluator =
+ new GlobalIndexEvaluator(
+ rowType,
+ fieldId -> Collections.singletonList(new
StubGlobalIndexReader(null)));
+
+ Optional<GlobalIndexResult> result =
+ evaluator.evaluate(new PredicateBuilder(rowType).isNaN(0));
+
+ assertThat(result).isEmpty();
+ evaluator.close();
+ }
+
+ @Test
+ void testNotBetweenThroughUnionAndOffset() {
+ RowType rowType = rowType();
+ GlobalIndexReader delegate =
+ new StubGlobalIndexReader(null) {
+ @Override
+ public CompletableFuture<Optional<GlobalIndexResult>>
visitNotBetween(
+ FieldRef fieldRef, Object from, Object to) {
+ return
CompletableFuture.completedFuture(Optional.of(resultOf(1, 3)));
+ }
+ };
+ GlobalIndexReader wrapped =
+ new UnionGlobalIndexReader(
+ Collections.singletonList(new
OffsetGlobalIndexReader(delegate, 10L, 20L)));
+ GlobalIndexEvaluator evaluator =
+ new GlobalIndexEvaluator(rowType, fieldId ->
Collections.singletonList(wrapped));
+ PredicateBuilder builder = new PredicateBuilder(rowType);
+
+ Optional<GlobalIndexResult> result =
+ evaluator.evaluate(builder.between(0, 1, 2).negate().get());
+
+ assertThat(result).isPresent();
+ assertBitmapContainsExactly(result.get().results(), 11L, 13L);
+ evaluator.close();
+ }
+
+ @Test
+ void testWrappedUnsupportedRangePredicatesFallBack() {
+ RowType rowType = rowType();
+ GlobalIndexReader wrapped =
+ new UnionGlobalIndexReader(
+ Collections.singletonList(
+ new OffsetGlobalIndexReader(
+ new StubGlobalIndexReader(null), 10L,
20L)));
+ GlobalIndexEvaluator evaluator =
+ new GlobalIndexEvaluator(rowType, fieldId ->
Collections.singletonList(wrapped));
+ PredicateBuilder builder = new PredicateBuilder(rowType);
+
+ assertThat(evaluator.evaluate(builder.between(0, 1,
2).negate().get())).isEmpty();
+ assertThat(evaluator.evaluate(builder.between(0, 1, 2))).isEmpty();
+ evaluator.close();
+ }
+
+ @Test
+ void testConstantReaderReturnsFixedResultForIsNaNAndNotBetween() {
+ GlobalIndexResult expected = resultOf(1, 2);
+ GlobalIndexReader reader = new ConstantGlobalIndexReader(expected);
+ FieldRef fieldRef = new FieldRef(0, "a", DataTypes.DOUBLE());
+
+ assertThat(reader.visitIsNaN(fieldRef).join()).contains(expected);
+ assertThat(reader.visitNotBetween(fieldRef, 1,
2).join()).contains(expected);
+ }
+
@Test
void testNullPredicate() {
RowType rowType = rowType();