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

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 673828c7c2e Replace SingleValueVisitor/MultiValueVisitor with 
per-predicate visitors (#18297)
673828c7c2e is described below

commit 673828c7c2effcff254a36ac81614b431d798dd3
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Thu Apr 23 00:20:38 2026 -0700

    Replace SingleValueVisitor/MultiValueVisitor with per-predicate visitors 
(#18297)
    
    Each raw predicate evaluator (EQ, NOT_EQ, IN, NOT_IN, RANGE) now defines its
    own nested Visitor<R> interface whose methods match the shape of the 
predicate:
    - EQ/NOT_EQ: single (non-)matching value
    - IN/NOT_IN: (non-)matching values delivered as the underlying typed set
      (IntSet, LongSet, ..., SortedSet<BigDecimal>, Set<String>, 
Set<ByteArray>),
      avoiding array conversions at the accept callsite
    - RANGE: inclusive bounds for int/long/float/double; lower/upper with
      inclusivity flags for BigDecimal/String/Bytes (new - RANGE previously had
      no visitor)
    
    Removed the shared SingleValueVisitor and MultiValueVisitor interfaces from
    pinot-spi along with their never-reached 
visitBoolean/visitTimestamp/visitJson
    methods (BOOLEAN/TIMESTAMP/JSON are always routed through the 
Int/Long/String
    evaluators).
    
    Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
 .../predicate/EqualsPredicateEvaluatorFactory.java | 47 +++++-----
 .../predicate/InPredicateEvaluatorFactory.java     | 57 ++++++++-----
 .../NotEqualsPredicateEvaluatorFactory.java        | 42 +++++----
 .../predicate/NotInPredicateEvaluatorFactory.java  | 57 ++++++++-----
 .../predicate/RangePredicateEvaluatorFactory.java  | 98 +++++++++++++++++++--
 .../predicate/InPredicateEvaluatorFactoryTest.java | 79 ++++++++---------
 .../apache/pinot/spi/data/MultiValueVisitor.java   | 99 ----------------------
 .../apache/pinot/spi/data/SingleValueVisitor.java  | 45 ----------
 8 files changed, 248 insertions(+), 276 deletions(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
index d99b8249d45..1bfe549b00e 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
@@ -28,8 +28,6 @@ import 
org.apache.pinot.core.operator.filter.predicate.traits.IntValue;
 import org.apache.pinot.core.operator.filter.predicate.traits.LongValue;
 import org.apache.pinot.segment.spi.index.reader.Dictionary;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
-import org.apache.pinot.spi.data.MultiValueVisitor;
-import org.apache.pinot.spi.data.SingleValueVisitor;
 import org.apache.pinot.spi.utils.BooleanUtils;
 import org.apache.pinot.spi.utils.BytesUtils;
 import org.apache.pinot.spi.utils.TimestampUtils;
@@ -147,16 +145,24 @@ public class EqualsPredicateEvaluatorFactory {
       super(predicate);
     }
 
-    /**
-     * Visits the matching value of this predicate.
-     */
-    public abstract <R> R accept(SingleValueVisitor<R> visitor);
+    /// Visits the matching value of this predicate.
+    public abstract <R> R accept(Visitor<R> visitor);
 
-    /**
-     * Visits the matching value of this predicate, which will be transformed 
into an array with a single value.
-     */
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return accept(visitor.asSingleValueVisitor());
+    /// Visitor for the matching value of an EQ predicate, dispatched by the 
stored value type.
+    public interface Visitor<R> {
+      R visitInt(int matchingValue);
+
+      R visitLong(long matchingValue);
+
+      R visitFloat(float matchingValue);
+
+      R visitDouble(double matchingValue);
+
+      R visitBigDecimal(BigDecimal matchingValue);
+
+      R visitString(String matchingValue);
+
+      R visitBytes(byte[] matchingValue);
     }
   }
 
@@ -169,7 +175,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitInt(_matchingValue);
     }
 
@@ -217,15 +223,10 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitLong(_matchingValue);
     }
 
-    @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.asSingleValueVisitor().visitLong(_matchingValue);
-    }
-
     @Override
     public int getNumMatchingItems() {
       return 1;
@@ -270,7 +271,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitFloat(_matchingValue);
     }
 
@@ -318,7 +319,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitDouble(_matchingValue);
     }
 
@@ -365,7 +366,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitBigDecimal(_matchingValue);
     }
 
@@ -394,7 +395,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitString(_matchingValue);
     }
 
@@ -423,7 +424,7 @@ public class EqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitBytes(_matchingValue);
     }
 
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactory.java
index ed7fb5273ff..ebf6b5839fd 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactory.java
@@ -31,6 +31,7 @@ import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
 import java.util.TreeSet;
 import javax.annotation.Nullable;
 import org.apache.pinot.common.request.context.predicate.InPredicate;
@@ -39,7 +40,6 @@ import org.apache.pinot.common.utils.HashUtil;
 import org.apache.pinot.core.query.request.context.QueryContext;
 import org.apache.pinot.segment.spi.index.reader.Dictionary;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
-import org.apache.pinot.spi.data.MultiValueVisitor;
 import org.apache.pinot.spi.utils.ByteArray;
 
 
@@ -206,10 +206,28 @@ public class InPredicateEvaluatorFactory {
       super(predicate);
     }
 
-    /**
-     * Visits the matching value of this predicate.
-     */
-    public abstract <R> R accept(MultiValueVisitor<R> visitor);
+    /// Visits the matching values of this predicate.
+    public abstract <R> R accept(Visitor<R> visitor);
+
+    /// Visitor for the matching values of an IN predicate, dispatched by the 
stored value type.
+    ///
+    /// The `BigDecimal` matching values are delivered in a [SortedSet] 
because `BigDecimal`'s `compareTo` is not
+    /// consistent with `equals` (e.g. `3.0` and `3` compare equal).
+    public interface Visitor<R> {
+      R visitInt(IntSet matchingValues);
+
+      R visitLong(LongSet matchingValues);
+
+      R visitFloat(FloatSet matchingValues);
+
+      R visitDouble(DoubleSet matchingValues);
+
+      R visitBigDecimal(SortedSet<BigDecimal> matchingValues);
+
+      R visitString(Set<String> matchingValues);
+
+      R visitBytes(Set<ByteArray> matchingValues);
+    }
   }
 
   private static final class IntRawValueBasedInPredicateEvaluator extends 
InRawPredicateEvaluator {
@@ -249,8 +267,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitInt(_matchingValues.toIntArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitInt(_matchingValues);
     }
   }
 
@@ -291,8 +309,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitLong(_matchingValues.toLongArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitLong(_matchingValues);
     }
   }
 
@@ -333,8 +351,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitFloat(_matchingValues.toFloatArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitFloat(_matchingValues);
     }
   }
 
@@ -375,8 +393,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitDouble(_matchingValues.toDoubleArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitDouble(_matchingValues);
     }
   }
 
@@ -410,8 +428,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitBigDecimal(_matchingValues.toArray(new 
BigDecimal[0]));
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBigDecimal(_matchingValues);
     }
   }
 
@@ -439,8 +457,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitString(_matchingValues.toArray(new String[0]));
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitString(_matchingValues);
     }
   }
 
@@ -468,9 +486,8 @@ public class InPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      byte[][] bytes = 
_matchingValues.stream().map(ByteArray::getBytes).toArray(byte[][]::new);
-      return visitor.visitBytes(bytes);
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBytes(_matchingValues);
     }
   }
 }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotEqualsPredicateEvaluatorFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotEqualsPredicateEvaluatorFactory.java
index 742b69c1b19..e5539076e26 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotEqualsPredicateEvaluatorFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotEqualsPredicateEvaluatorFactory.java
@@ -24,8 +24,6 @@ import 
org.apache.pinot.common.request.context.predicate.NotEqPredicate;
 import org.apache.pinot.common.request.context.predicate.Predicate;
 import org.apache.pinot.segment.spi.index.reader.Dictionary;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
-import org.apache.pinot.spi.data.MultiValueVisitor;
-import org.apache.pinot.spi.data.SingleValueVisitor;
 import org.apache.pinot.spi.utils.BooleanUtils;
 import org.apache.pinot.spi.utils.BytesUtils;
 import org.apache.pinot.spi.utils.TimestampUtils;
@@ -137,16 +135,24 @@ public class NotEqualsPredicateEvaluatorFactory {
       super(predicate);
     }
 
-    /**
-     * Visits the not matching value of this predicate.
-     */
-    public abstract <R> R accept(SingleValueVisitor<R> visitor);
+    /// Visits the non-matching value of this predicate.
+    public abstract <R> R accept(Visitor<R> visitor);
 
-    /**
-     * Visits the not matching value of this predicate, which will be 
transformed into an array with a single value.
-     */
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return accept(visitor.asSingleValueVisitor());
+    /// Visitor for the non-matching value of a NOT_EQ predicate, dispatched 
by the stored value type.
+    public interface Visitor<R> {
+      R visitInt(int nonMatchingValue);
+
+      R visitLong(long nonMatchingValue);
+
+      R visitFloat(float nonMatchingValue);
+
+      R visitDouble(double nonMatchingValue);
+
+      R visitBigDecimal(BigDecimal nonMatchingValue);
+
+      R visitString(String nonMatchingValue);
+
+      R visitBytes(byte[] nonMatchingValue);
     }
   }
 
@@ -187,7 +193,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitInt(_nonMatchingValue);
     }
   }
@@ -229,7 +235,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitLong(_nonMatchingValue);
     }
   }
@@ -271,7 +277,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitFloat(_nonMatchingValue);
     }
   }
@@ -313,7 +319,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitDouble(_nonMatchingValue);
     }
   }
@@ -342,7 +348,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitBigDecimal(_nonMatchingValue);
     }
   }
@@ -371,7 +377,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitString(_nonMatchingValue);
     }
   }
@@ -400,7 +406,7 @@ public class NotEqualsPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(SingleValueVisitor<R> visitor) {
+    public <R> R accept(Visitor<R> visitor) {
       return visitor.visitBytes(_nonMatchingValue);
     }
   }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotInPredicateEvaluatorFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotInPredicateEvaluatorFactory.java
index daabde10694..2cdf47874e5 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotInPredicateEvaluatorFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/NotInPredicateEvaluatorFactory.java
@@ -31,6 +31,7 @@ import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
 import java.util.TreeSet;
 import javax.annotation.Nullable;
 import org.apache.pinot.common.request.context.predicate.NotInPredicate;
@@ -39,7 +40,6 @@ import org.apache.pinot.common.utils.HashUtil;
 import org.apache.pinot.core.query.request.context.QueryContext;
 import org.apache.pinot.segment.spi.index.reader.Dictionary;
 import org.apache.pinot.spi.data.FieldSpec.DataType;
-import org.apache.pinot.spi.data.MultiValueVisitor;
 import org.apache.pinot.spi.utils.ByteArray;
 
 
@@ -211,10 +211,28 @@ public class NotInPredicateEvaluatorFactory {
       super(predicate);
     }
 
-    /**
-     * Visits the not matching value of this predicate.
-     */
-    public abstract <R> R accept(MultiValueVisitor<R> visitor);
+    /// Visits the non-matching values of this predicate.
+    public abstract <R> R accept(Visitor<R> visitor);
+
+    /// Visitor for the non-matching values of a NOT_IN predicate, dispatched 
by the stored value type.
+    ///
+    /// The `BigDecimal` non-matching values are delivered in a [SortedSet] 
because `BigDecimal`'s `compareTo` is not
+    /// consistent with `equals` (e.g. `3.0` and `3` compare equal).
+    public interface Visitor<R> {
+      R visitInt(IntSet nonMatchingValues);
+
+      R visitLong(LongSet nonMatchingValues);
+
+      R visitFloat(FloatSet nonMatchingValues);
+
+      R visitDouble(DoubleSet nonMatchingValues);
+
+      R visitBigDecimal(SortedSet<BigDecimal> nonMatchingValues);
+
+      R visitString(Set<String> nonMatchingValues);
+
+      R visitBytes(Set<ByteArray> nonMatchingValues);
+    }
   }
 
   private static final class IntRawValueBasedNotInPredicateEvaluator extends 
NotInRawPredicateEvaluator {
@@ -254,8 +272,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitInt(_nonMatchingValues.toIntArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitInt(_nonMatchingValues);
     }
   }
 
@@ -296,8 +314,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitLong(_nonMatchingValues.toLongArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitLong(_nonMatchingValues);
     }
   }
 
@@ -338,8 +356,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitFloat(_nonMatchingValues.toFloatArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitFloat(_nonMatchingValues);
     }
   }
 
@@ -380,8 +398,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitDouble(_nonMatchingValues.toDoubleArray());
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitDouble(_nonMatchingValues);
     }
   }
 
@@ -411,8 +429,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitBigDecimal(_nonMatchingValues.toArray(new 
BigDecimal[0]));
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBigDecimal(_nonMatchingValues);
     }
   }
 
@@ -440,8 +458,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      return visitor.visitString(_nonMatchingValues.toArray(new String[0]));
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitString(_nonMatchingValues);
     }
   }
 
@@ -469,9 +487,8 @@ public class NotInPredicateEvaluatorFactory {
     }
 
     @Override
-    public <R> R accept(MultiValueVisitor<R> visitor) {
-      byte[][] bytes = 
_nonMatchingValues.stream().map(ByteArray::getBytes).toArray(byte[][]::new);
-      return visitor.visitBytes(bytes);
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBytes(_nonMatchingValues);
     }
   }
 }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
index e9bd3b4b0a7..6b7c12be359 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
@@ -21,6 +21,8 @@ package org.apache.pinot.core.operator.filter.predicate;
 import com.google.common.base.Preconditions;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import java.math.BigDecimal;
+import javax.annotation.Nullable;
+import org.apache.pinot.common.request.context.predicate.Predicate;
 import org.apache.pinot.common.request.context.predicate.RangePredicate;
 import org.apache.pinot.core.operator.filter.predicate.traits.DoubleRange;
 import org.apache.pinot.core.operator.filter.predicate.traits.FloatRange;
@@ -65,7 +67,7 @@ public class RangePredicateEvaluatorFactory {
    * @param dataType Data type for the column
    * @return Raw value based RANGE predicate evaluator
    */
-  public static BaseRawValueBasedPredicateEvaluator 
newRawValueBasedEvaluator(RangePredicate rangePredicate,
+  public static RangeRawPredicateEvaluator 
newRawValueBasedEvaluator(RangePredicate rangePredicate,
       DataType dataType) {
     String lowerBound = rangePredicate.getLowerBound();
     String upperBound = rangePredicate.getUpperBound();
@@ -323,7 +325,40 @@ public class RangePredicateEvaluatorFactory {
     }
   }
 
-  private static final class IntRawValueBasedRangePredicateEvaluator extends 
BaseRawValueBasedPredicateEvaluator
+  public static abstract class RangeRawPredicateEvaluator extends 
BaseRawValueBasedPredicateEvaluator {
+    public RangeRawPredicateEvaluator(Predicate predicate) {
+      super(predicate);
+    }
+
+    /// Visits the bounds of this predicate.
+    public abstract <R> R accept(Visitor<R> visitor);
+
+    /// Visitor for the bounds of a RANGE predicate, dispatched by the stored 
value type.
+    ///
+    /// For integral and floating point types, exclusive bounds are normalized 
to inclusive bounds, and unbounded
+    /// sides are normalized to the data type's min/max. For `BigDecimal`, 
`String`, and `byte[]`, the raw bounds are
+    /// passed through together with their inclusivity flags, and unbounded 
sides are represented by a `null` bound.
+    public interface Visitor<R> {
+      R visitInt(int inclusiveLowerBound, int inclusiveUpperBound);
+
+      R visitLong(long inclusiveLowerBound, long inclusiveUpperBound);
+
+      R visitFloat(float inclusiveLowerBound, float inclusiveUpperBound);
+
+      R visitDouble(double inclusiveLowerBound, double inclusiveUpperBound);
+
+      R visitBigDecimal(@Nullable BigDecimal lowerBound, @Nullable BigDecimal 
upperBound, boolean lowerInclusive,
+          boolean upperInclusive);
+
+      R visitString(@Nullable String lowerBound, @Nullable String upperBound, 
boolean lowerInclusive,
+          boolean upperInclusive);
+
+      R visitBytes(@Nullable byte[] lowerBound, @Nullable byte[] upperBound, 
boolean lowerInclusive,
+          boolean upperInclusive);
+    }
+  }
+
+  private static final class IntRawValueBasedRangePredicateEvaluator extends 
RangeRawPredicateEvaluator
       implements IntRange {
     final int _inclusiveLowerBound;
     final int _inclusiveUpperBound;
@@ -377,9 +412,14 @@ public class RangePredicateEvaluatorFactory {
       }
       return matches;
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitInt(_inclusiveLowerBound, _inclusiveUpperBound);
+    }
   }
 
-  private static final class LongRawValueBasedRangePredicateEvaluator extends 
BaseRawValueBasedPredicateEvaluator
+  private static final class LongRawValueBasedRangePredicateEvaluator extends 
RangeRawPredicateEvaluator
       implements LongRange {
     final long _inclusiveLowerBound;
     final long _inclusiveUpperBound;
@@ -433,9 +473,14 @@ public class RangePredicateEvaluatorFactory {
       }
       return matches;
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitLong(_inclusiveLowerBound, _inclusiveUpperBound);
+    }
   }
 
-  private static final class FloatRawValueBasedRangePredicateEvaluator extends 
BaseRawValueBasedPredicateEvaluator
+  private static final class FloatRawValueBasedRangePredicateEvaluator extends 
RangeRawPredicateEvaluator
       implements FloatRange {
     final float _inclusiveLowerBound;
     final float _inclusiveUpperBound;
@@ -489,9 +534,14 @@ public class RangePredicateEvaluatorFactory {
       }
       return matches;
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitFloat(_inclusiveLowerBound, _inclusiveUpperBound);
+    }
   }
 
-  private static final class DoubleRawValueBasedRangePredicateEvaluator 
extends BaseRawValueBasedPredicateEvaluator
+  private static final class DoubleRawValueBasedRangePredicateEvaluator 
extends RangeRawPredicateEvaluator
       implements DoubleRange {
     final double _inclusiveLowerBound;
     final double _inclusiveUpperBound;
@@ -545,11 +595,18 @@ public class RangePredicateEvaluatorFactory {
       }
       return matches;
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitDouble(_inclusiveLowerBound, _inclusiveUpperBound);
+    }
   }
 
-  public static final class BigDecimalRawValueBasedRangePredicateEvaluator 
extends BaseRawValueBasedPredicateEvaluator {
+  public static final class BigDecimalRawValueBasedRangePredicateEvaluator 
extends RangeRawPredicateEvaluator {
     final BigDecimal _lowerBound;
     final BigDecimal _upperBound;
+    final boolean _lowerInclusive;
+    final boolean _upperInclusive;
     final int _lowerComparisonValue;
     final int _upperComparisonValue;
 
@@ -558,6 +615,8 @@ public class RangePredicateEvaluatorFactory {
       super(rangePredicate);
       _lowerBound = lowerBound;
       _upperBound = upperBound;
+      _lowerInclusive = lowerInclusive;
+      _upperInclusive = upperInclusive;
       _lowerComparisonValue = lowerInclusive ? 0 : 1;
       _upperComparisonValue = upperInclusive ? 0 : -1;
     }
@@ -572,11 +631,18 @@ public class RangePredicateEvaluatorFactory {
       return (_lowerBound == null || value.compareTo(_lowerBound) >= 
_lowerComparisonValue) && (_upperBound == null
           || value.compareTo(_upperBound) <= _upperComparisonValue);
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBigDecimal(_lowerBound, _upperBound, 
_lowerInclusive, _upperInclusive);
+    }
   }
 
-  private static final class StringRawValueBasedRangePredicateEvaluator 
extends BaseRawValueBasedPredicateEvaluator {
+  private static final class StringRawValueBasedRangePredicateEvaluator 
extends RangeRawPredicateEvaluator {
     final String _lowerBound;
     final String _upperBound;
+    final boolean _lowerInclusive;
+    final boolean _upperInclusive;
     final int _lowerComparisonValue;
     final int _upperComparisonValue;
 
@@ -585,6 +651,8 @@ public class RangePredicateEvaluatorFactory {
       super(rangePredicate);
       _lowerBound = lowerBound;
       _upperBound = upperBound;
+      _lowerInclusive = lowerInclusive;
+      _upperInclusive = upperInclusive;
       _lowerComparisonValue = lowerInclusive ? 0 : 1;
       _upperComparisonValue = upperInclusive ? 0 : -1;
     }
@@ -599,11 +667,18 @@ public class RangePredicateEvaluatorFactory {
       return (_lowerBound == null || value.compareTo(_lowerBound) >= 
_lowerComparisonValue) && (_upperBound == null
           || value.compareTo(_upperBound) <= _upperComparisonValue);
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitString(_lowerBound, _upperBound, _lowerInclusive, 
_upperInclusive);
+    }
   }
 
-  private static final class BytesRawValueBasedRangePredicateEvaluator extends 
BaseRawValueBasedPredicateEvaluator {
+  private static final class BytesRawValueBasedRangePredicateEvaluator extends 
RangeRawPredicateEvaluator {
     final byte[] _lowerBound;
     final byte[] _upperBound;
+    final boolean _lowerInclusive;
+    final boolean _upperInclusive;
     final int _lowerComparisonValue;
     final int _upperComparisonValue;
 
@@ -612,6 +687,8 @@ public class RangePredicateEvaluatorFactory {
       super(rangePredicate);
       _lowerBound = lowerBound;
       _upperBound = upperBound;
+      _lowerInclusive = lowerInclusive;
+      _upperInclusive = upperInclusive;
       _lowerComparisonValue = lowerInclusive ? 0 : 1;
       _upperComparisonValue = upperInclusive ? 0 : -1;
     }
@@ -626,5 +703,10 @@ public class RangePredicateEvaluatorFactory {
       return (_lowerBound == null || ByteArray.compare(value, _lowerBound) >= 
_lowerComparisonValue) && (
           _upperBound == null || ByteArray.compare(value, _upperBound) <= 
_upperComparisonValue);
     }
+
+    @Override
+    public <R> R accept(Visitor<R> visitor) {
+      return visitor.visitBytes(_lowerBound, _upperBound, _lowerInclusive, 
_upperInclusive);
+    }
   }
 }
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactoryTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactoryTest.java
index 8e83e2b2177..bea79ab3569 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactoryTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/predicate/InPredicateEvaluatorFactoryTest.java
@@ -19,11 +19,19 @@
 package org.apache.pinot.core.operator.filter.predicate;
 
 import com.google.common.collect.Lists;
+import it.unimi.dsi.fastutil.doubles.DoubleSet;
+import it.unimi.dsi.fastutil.floats.FloatSet;
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import it.unimi.dsi.fastutil.ints.IntSet;
+import it.unimi.dsi.fastutil.longs.LongSet;
 import java.math.BigDecimal;
+import java.util.Set;
+import java.util.SortedSet;
 import org.apache.pinot.common.request.context.ExpressionContext;
 import org.apache.pinot.common.request.context.predicate.InPredicate;
+import 
org.apache.pinot.core.operator.filter.predicate.InPredicateEvaluatorFactory.InRawPredicateEvaluator;
 import org.apache.pinot.spi.data.FieldSpec;
-import org.apache.pinot.spi.data.MultiValueVisitor;
+import org.apache.pinot.spi.utils.ByteArray;
 import org.mockito.Mockito;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -31,56 +39,41 @@ import org.testng.annotations.Test;
 
 public class InPredicateEvaluatorFactoryTest {
 
-  MultiValueVisitor<Integer> createValueLengthVisitor() {
-    return new MultiValueVisitor<Integer>() {
+  InRawPredicateEvaluator.Visitor<Integer> createValueSizeVisitor() {
+    return new InRawPredicateEvaluator.Visitor<>() {
       @Override
-      public Integer visitInt(int[] value) {
-        return value.length;
+      public Integer visitInt(IntSet matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitLong(long[] value) {
-        return value.length;
+      public Integer visitLong(LongSet matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitFloat(float[] value) {
-        return value.length;
+      public Integer visitFloat(FloatSet matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitDouble(double[] value) {
-        return value.length;
+      public Integer visitDouble(DoubleSet matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitBigDecimal(BigDecimal[] value) {
-        return value.length;
+      public Integer visitBigDecimal(SortedSet<BigDecimal> matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitBoolean(boolean[] value) {
-        return value.length;
+      public Integer visitString(Set<String> matchingValues) {
+        return matchingValues.size();
       }
 
       @Override
-      public Integer visitTimestamp(long[] value) {
-        return value.length;
-      }
-
-      @Override
-      public Integer visitString(String[] value) {
-        return value.length;
-      }
-
-      @Override
-      public Integer visitJson(String[] value) {
-        return value.length;
-      }
-
-      @Override
-      public Integer visitBytes(byte[][] value) {
-        return value.length;
+      public Integer visitBytes(Set<ByteArray> matchingValues) {
+        return matchingValues.size();
       }
     };
   }
@@ -88,7 +81,7 @@ public class InPredicateEvaluatorFactoryTest {
   @Test
   void canBeVisited() {
     // Given a visitor
-    MultiValueVisitor<Integer> valueLengthVisitor = 
Mockito.spy(createValueLengthVisitor());
+    InRawPredicateEvaluator.Visitor<Integer> valueSizeVisitor = 
Mockito.spy(createValueSizeVisitor());
 
     // When int predicate is used
     InPredicate predicate = new 
InPredicate(ExpressionContext.forIdentifier("ident"), Lists.newArrayList("1", 
"2"));
@@ -96,20 +89,20 @@ public class InPredicateEvaluatorFactoryTest {
     InPredicateEvaluatorFactory.InRawPredicateEvaluator intEvaluator =
         InPredicateEvaluatorFactory.newRawValueBasedEvaluator(predicate, 
FieldSpec.DataType.INT);
 
-    // Only the int[] method is called
-    int length = intEvaluator.accept(valueLengthVisitor);
-    Assert.assertEquals(length, 2);
-    Mockito.verify(valueLengthVisitor).visitInt(new int[] {2, 1});
-    Mockito.verifyNoMoreInteractions(valueLengthVisitor);
+    // Only the IntSet method is called
+    int size = intEvaluator.accept(valueSizeVisitor);
+    Assert.assertEquals(size, 2);
+    Mockito.verify(valueSizeVisitor).visitInt(new IntOpenHashSet(new int[] {1, 
2}));
+    Mockito.verifyNoMoreInteractions(valueSizeVisitor);
 
     // And given a string predicate
     InPredicateEvaluatorFactory.InRawPredicateEvaluator strEvaluator =
         InPredicateEvaluatorFactory.newRawValueBasedEvaluator(predicate, 
FieldSpec.DataType.STRING);
 
-    // Only the string[] method is called
-    length = strEvaluator.accept(valueLengthVisitor);
-    Assert.assertEquals(length, 2);
-    Mockito.verify(valueLengthVisitor).visitString(new String[] {"2", "1"});
-    Mockito.verifyNoMoreInteractions(valueLengthVisitor);
+    // Only the Set<String> method is called
+    size = strEvaluator.accept(valueSizeVisitor);
+    Assert.assertEquals(size, 2);
+    Mockito.verify(valueSizeVisitor).visitString(Set.of("1", "2"));
+    Mockito.verifyNoMoreInteractions(valueSizeVisitor);
   }
 }
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/data/MultiValueVisitor.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/data/MultiValueVisitor.java
deleted file mode 100644
index 13fc4d3568b..00000000000
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/data/MultiValueVisitor.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * 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.pinot.spi.data;
-
-import java.math.BigDecimal;
-
-
-public interface MultiValueVisitor<R> {
-
-  R visitInt(int[] value);
-
-  R visitLong(long[] value);
-
-  R visitFloat(float[] value);
-
-  R visitDouble(double[] value);
-
-  R visitBigDecimal(BigDecimal[] value);
-
-  R visitBoolean(boolean[] value);
-
-  R visitTimestamp(long[] value);
-
-  R visitString(String[] value);
-
-  R visitJson(String[] value);
-
-  R visitBytes(byte[][] value);
-
-  default SingleValueVisitor<R> asSingleValueVisitor() {
-    return new SingleValueVisitor<R>() {
-      @Override
-      public R visitInt(int value) {
-        return MultiValueVisitor.this.visitInt(new int[] {value});
-      }
-
-      @Override
-      public R visitLong(long value) {
-        return MultiValueVisitor.this.visitLong(new long[] {value});
-      }
-
-      @Override
-      public R visitFloat(float value) {
-        return MultiValueVisitor.this.visitFloat(new float[] {value});
-      }
-
-      @Override
-      public R visitDouble(double value) {
-        return MultiValueVisitor.this.visitDouble(new double[] {value});
-      }
-
-      @Override
-      public R visitBigDecimal(BigDecimal value) {
-        return MultiValueVisitor.this.visitBigDecimal(new BigDecimal[] 
{value});
-      }
-
-      @Override
-      public R visitBoolean(boolean value) {
-        return MultiValueVisitor.this.visitBoolean(new boolean[] {value});
-      }
-
-      @Override
-      public R visitTimestamp(long value) {
-        return MultiValueVisitor.this.visitLong(new long[] {value});
-      }
-
-      @Override
-      public R visitString(String value) {
-        return MultiValueVisitor.this.visitString(new String[] {value});
-      }
-
-      @Override
-      public R visitJson(String value) {
-        return MultiValueVisitor.this.visitString(new String[] {value});
-      }
-
-      @Override
-      public R visitBytes(byte[] value) {
-        return MultiValueVisitor.this.visitBytes(new byte[][] {value});
-      }
-    };
-  }
-}
diff --git 
a/pinot-spi/src/main/java/org/apache/pinot/spi/data/SingleValueVisitor.java 
b/pinot-spi/src/main/java/org/apache/pinot/spi/data/SingleValueVisitor.java
deleted file mode 100644
index 6184bbf057a..00000000000
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/data/SingleValueVisitor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * 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.pinot.spi.data;
-
-import java.math.BigDecimal;
-
-
-public interface SingleValueVisitor<R> {
-
-  R visitInt(int value);
-
-  R visitLong(long value);
-
-  R visitFloat(float value);
-
-  R visitDouble(double value);
-
-  R visitBigDecimal(BigDecimal value);
-
-  R visitBoolean(boolean value);
-
-  R visitTimestamp(long value);
-
-  R visitString(String value);
-
-  R visitJson(String value);
-
-  R visitBytes(byte[] value);
-}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to