You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ja...@apache.org on 2023/11/07 16:48:00 UTC

(pinot) branch master updated: Support constant filter in QueryContext, and make server able to handle it (#11956)

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

jackie 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 45f186903e Support constant filter in QueryContext, and make server able to handle it (#11956)
45f186903e is described below

commit 45f186903e0d35304fb764ccb5f1423839d3276b
Author: Xiaotian (Jackie) Jiang <17...@users.noreply.github.com>
AuthorDate: Tue Nov 7 08:47:54 2023 -0800

    Support constant filter in QueryContext, and make server able to handle it (#11956)
---
 .../common/request/context/FilterContext.java      |  73 +++++--
 .../request/context/RequestContextUtils.java       | 236 +++++++++++++--------
 .../controller/recommender/io/InputManager.java    |   8 +-
 .../recommender/rules/impl/BloomFilterRule.java    |   7 +-
 .../recommender/rules/impl/FlagQueryRule.java      |   6 +-
 .../NoDictionaryOnHeapDictionaryJointRule.java     |   5 +-
 .../rules/impl/PinotTablePartitionRule.java        |   7 +-
 .../recommender/rules/impl/RangeIndexRule.java     |   5 +-
 .../utils/QueryInvertedSortedIndexRecommender.java |   7 +-
 ...istinctCountThetaSketchAggregationFunction.java |   2 +-
 .../query/executor/ServerQueryExecutorV1Impl.java  |  23 +-
 .../context/utils/QueryContextConverterUtils.java  |   8 +
 .../BrokerRequestToQueryContextConverterTest.java  |  89 ++++++--
 .../realtime/impl/json/MutableJsonIndexImpl.java   |   1 +
 .../readers/json/ImmutableJsonIndexReader.java     |   1 +
 15 files changed, 330 insertions(+), 148 deletions(-)

diff --git a/pinot-common/src/main/java/org/apache/pinot/common/request/context/FilterContext.java b/pinot-common/src/main/java/org/apache/pinot/common/request/context/FilterContext.java
index aa76809b68..3ce48fd06c 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/request/context/FilterContext.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/request/context/FilterContext.java
@@ -18,9 +18,11 @@
  */
 package org.apache.pinot.common.request.context;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import javax.annotation.Nullable;
 import org.apache.pinot.common.request.context.predicate.Predicate;
 
 
@@ -29,22 +31,50 @@ import org.apache.pinot.common.request.context.predicate.Predicate;
  * clause are modeled as a filter.
  */
 public class FilterContext {
+  public static final FilterContext CONSTANT_TRUE = new FilterContext(Type.CONSTANT, null, null, true);
+  public static final FilterContext CONSTANT_FALSE = new FilterContext(Type.CONSTANT, null, null, false);
+
   public enum Type {
-    AND, OR, NOT, PREDICATE
+    AND, OR, NOT, PREDICATE, CONSTANT
   }
 
   private final Type _type;
 
-  // For AND and OR
+  // For AND, OR, NOT
   private final List<FilterContext> _children;
 
   // For Predicate
   private final Predicate _predicate;
 
-  public FilterContext(Type type, List<FilterContext> children, Predicate predicate) {
+  // For Constant
+  private final boolean _isTrue;
+
+  private FilterContext(Type type, @Nullable List<FilterContext> children, @Nullable Predicate predicate,
+      boolean isTrue) {
     _type = type;
     _children = children;
     _predicate = predicate;
+    _isTrue = isTrue;
+  }
+
+  public static FilterContext forAnd(List<FilterContext> children) {
+    return new FilterContext(Type.AND, children, null, false);
+  }
+
+  public static FilterContext forOr(List<FilterContext> children) {
+    return new FilterContext(Type.OR, children, null, false);
+  }
+
+  public static FilterContext forNot(FilterContext child) {
+    return new FilterContext(Type.NOT, Collections.singletonList(child), null, false);
+  }
+
+  public static FilterContext forPredicate(Predicate predicate) {
+    return new FilterContext(Type.PREDICATE, null, predicate, false);
+  }
+
+  public static FilterContext forConstant(boolean isTrue) {
+    return isTrue ? CONSTANT_TRUE : CONSTANT_FALSE;
   }
 
   public Type getType() {
@@ -59,6 +89,18 @@ public class FilterContext {
     return _predicate;
   }
 
+  public boolean isConstant() {
+    return _type == Type.CONSTANT;
+  }
+
+  public boolean isConstantTrue() {
+    return _isTrue;
+  }
+
+  public boolean isConstantFalse() {
+    return _type == Type.CONSTANT && !_isTrue;
+  }
+
   /**
    * Adds the columns (IDENTIFIER expressions) in the filter to the given set.
    */
@@ -67,7 +109,7 @@ public class FilterContext {
       for (FilterContext child : _children) {
         child.getColumns(columns);
       }
-    } else {
+    } else if (_predicate != null) {
       _predicate.getLhs().getColumns(columns);
     }
   }
@@ -81,37 +123,44 @@ public class FilterContext {
       return false;
     }
     FilterContext that = (FilterContext) o;
-    return _type == that._type && Objects.equals(_children, that._children) && Objects.equals(_predicate,
-        that._predicate);
+    return _isTrue == that._isTrue && _type == that._type && Objects.equals(_children, that._children)
+        && Objects.equals(_predicate, that._predicate);
   }
 
   @Override
   public int hashCode() {
-    return Objects.hash(_type, _children, _predicate);
+    return Objects.hash(_type, _children, _predicate, _isTrue);
   }
 
   @Override
   public String toString() {
     switch (_type) {
-      case AND:
+      case AND: {
+        assert _children != null;
         StringBuilder stringBuilder = new StringBuilder().append('(').append(_children.get(0));
         int numChildren = _children.size();
         for (int i = 1; i < numChildren; i++) {
           stringBuilder.append(" AND ").append(_children.get(i));
         }
         return stringBuilder.append(')').toString();
-      case OR:
-        stringBuilder = new StringBuilder().append('(').append(_children.get(0));
-        numChildren = _children.size();
+      }
+      case OR: {
+        assert _children != null;
+        StringBuilder stringBuilder = new StringBuilder().append('(').append(_children.get(0));
+        int numChildren = _children.size();
         for (int i = 1; i < numChildren; i++) {
           stringBuilder.append(" OR ").append(_children.get(i));
         }
         return stringBuilder.append(')').toString();
+      }
       case NOT:
-        assert _children.size() == 1;
+        assert _children != null && _children.size() == 1;
         return "(NOT " + _children.get(0) + ')';
       case PREDICATE:
+        assert _predicate != null;
         return _predicate.toString();
+      case CONSTANT:
+        return Boolean.toString(_isTrue);
       default:
         throw new IllegalStateException();
     }
diff --git a/pinot-common/src/main/java/org/apache/pinot/common/request/context/RequestContextUtils.java b/pinot-common/src/main/java/org/apache/pinot/common/request/context/RequestContextUtils.java
index 96bfb226e1..933f022bfb 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/request/context/RequestContextUtils.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/request/context/RequestContextUtils.java
@@ -111,11 +111,9 @@ public class RequestContextUtils {
         return getFilter(thriftFunction);
       case IDENTIFIER:
         // Convert "WHERE a" to "WHERE a = true"
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new EqPredicate(getExpression(thriftExpression), getStringValue(RequestUtils.getLiteralExpression(true))));
+        return FilterContext.forPredicate(new EqPredicate(getExpression(thriftExpression), "true"));
       case LITERAL:
-        // TODO: Handle literals.
-        throw new IllegalStateException();
+        return FilterContext.forConstant(new LiteralContext(thriftExpression.getLiteral()).getBooleanValue());
       default:
         throw new IllegalStateException();
     }
@@ -126,96 +124,127 @@ public class RequestContextUtils {
 
     // convert "WHERE startsWith(col, 'str')" to "WHERE startsWith(col, 'str') = true"
     if (!EnumUtils.isValidEnum(FilterKind.class, functionOperator)) {
-      return new FilterContext(FilterContext.Type.PREDICATE, null,
-          new EqPredicate(ExpressionContext.forFunction(getFunction(thriftFunction)),
-              getStringValue(RequestUtils.getLiteralExpression(true))));
+      return FilterContext.forPredicate(
+          new EqPredicate(ExpressionContext.forFunction(getFunction(thriftFunction)), "true"));
     }
 
     FilterKind filterKind = FilterKind.valueOf(thriftFunction.getOperator().toUpperCase());
     List<Expression> operands = thriftFunction.getOperands();
     int numOperands = operands.size();
     switch (filterKind) {
-      case AND:
+      case AND: {
         List<FilterContext> children = new ArrayList<>(numOperands);
         for (Expression operand : operands) {
-          children.add(getFilter(operand));
+          FilterContext filter = getFilter(operand);
+          if (!filter.isConstant()) {
+            children.add(filter);
+          } else {
+            if (filter.isConstantFalse()) {
+              return FilterContext.CONSTANT_FALSE;
+            }
+          }
+        }
+        int numChildren = children.size();
+        if (numChildren == 0) {
+          return FilterContext.CONSTANT_TRUE;
+        } else if (numChildren == 1) {
+          return children.get(0);
+        } else {
+          return FilterContext.forAnd(children);
         }
-        return new FilterContext(FilterContext.Type.AND, children, null);
-      case OR:
-        children = new ArrayList<>(numOperands);
+      }
+      case OR: {
+        List<FilterContext> children = new ArrayList<>(numOperands);
         for (Expression operand : operands) {
-          children.add(getFilter(operand));
+          FilterContext filter = getFilter(operand);
+          if (!filter.isConstant()) {
+            children.add(filter);
+          } else {
+            if (filter.isConstantTrue()) {
+              return FilterContext.CONSTANT_TRUE;
+            }
+          }
         }
-        return new FilterContext(FilterContext.Type.OR, children, null);
-      case NOT:
+        int numChildren = children.size();
+        if (numChildren == 0) {
+          return FilterContext.CONSTANT_FALSE;
+        } else if (numChildren == 1) {
+          return children.get(0);
+        } else {
+          return FilterContext.forOr(children);
+        }
+      }
+      case NOT: {
         assert numOperands == 1;
-        return new FilterContext(FilterContext.Type.NOT,
-            new ArrayList<>(Collections.singletonList(getFilter(operands.get(0)))), null);
+        FilterContext filter = getFilter(operands.get(0));
+        if (!filter.isConstant()) {
+          return FilterContext.forNot(filter);
+        } else {
+          return filter.isConstantTrue() ? FilterContext.CONSTANT_FALSE : FilterContext.CONSTANT_TRUE;
+        }
+      }
       case EQUALS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new EqPredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case NOT_EQUALS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new NotEqPredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
-      case IN:
+      case IN: {
         List<String> values = new ArrayList<>(numOperands - 1);
         for (int i = 1; i < numOperands; i++) {
           values.add(getStringValue(operands.get(i)));
         }
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new InPredicate(getExpression(operands.get(0)), values));
-      case NOT_IN:
-        values = new ArrayList<>(numOperands - 1);
+        return FilterContext.forPredicate(new InPredicate(getExpression(operands.get(0)), values));
+      }
+      case NOT_IN: {
+        List<String> values = new ArrayList<>(numOperands - 1);
         for (int i = 1; i < numOperands; i++) {
           values.add(getStringValue(operands.get(i)));
         }
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new NotInPredicate(getExpression(operands.get(0)), values));
+        return FilterContext.forPredicate(new NotInPredicate(getExpression(operands.get(0)), values));
+      }
       case GREATER_THAN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), false, getStringValue(operands.get(1)), false,
                 RangePredicate.UNBOUNDED));
       case GREATER_THAN_OR_EQUAL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), true, getStringValue(operands.get(1)), false,
                 RangePredicate.UNBOUNDED));
       case LESS_THAN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), false, RangePredicate.UNBOUNDED, false,
                 getStringValue(operands.get(1))));
       case LESS_THAN_OR_EQUAL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), false, RangePredicate.UNBOUNDED, true,
                 getStringValue(operands.get(1))));
       case BETWEEN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), true, getStringValue(operands.get(1)), true,
                 getStringValue(operands.get(2))));
       case RANGE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case REGEXP_LIKE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RegexpLikePredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case LIKE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new RegexpLikePredicate(getExpression(operands.get(0)),
-                RegexpPatternConverterUtils.likeToRegexpLike(getStringValue(operands.get(1)))));
+        return FilterContext.forPredicate(new RegexpLikePredicate(getExpression(operands.get(0)),
+            RegexpPatternConverterUtils.likeToRegexpLike(getStringValue(operands.get(1)))));
       case TEXT_CONTAINS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new TextContainsPredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case TEXT_MATCH:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new TextMatchPredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case JSON_MATCH:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new JsonMatchPredicate(getExpression(operands.get(0)), getStringValue(operands.get(1))));
       case IS_NULL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new IsNullPredicate(getExpression(operands.get(0))));
+        return FilterContext.forPredicate(new IsNullPredicate(getExpression(operands.get(0))));
       case IS_NOT_NULL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new IsNotNullPredicate(getExpression(operands.get(0))));
+        return FilterContext.forPredicate(new IsNotNullPredicate(getExpression(operands.get(0))));
       default:
         throw new IllegalStateException();
     }
@@ -245,11 +274,10 @@ public class RequestContextUtils {
         FunctionContext filterFunction = filterExpression.getFunction();
         return getFilter(filterFunction);
       case IDENTIFIER:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new EqPredicate(filterExpression, getStringValue(RequestUtils.getLiteralExpression(true))));
       case LITERAL:
-        // TODO: Handle literals
-        throw new IllegalStateException();
+        return FilterContext.forConstant(filterExpression.getLiteral().getBooleanValue());
       default:
         throw new IllegalStateException();
     }
@@ -260,91 +288,117 @@ public class RequestContextUtils {
 
     // convert "WHERE startsWith(col, 'str')" to "WHERE startsWith(col, 'str') = true"
     if (!EnumUtils.isValidEnum(FilterKind.class, functionOperator)) {
-      return new FilterContext(FilterContext.Type.PREDICATE, null,
-          new EqPredicate(ExpressionContext.forFunction(filterFunction),
-              getStringValue(RequestUtils.getLiteralExpression(true))));
+      return FilterContext.forPredicate(new EqPredicate(ExpressionContext.forFunction(filterFunction), "true"));
     }
 
     FilterKind filterKind = FilterKind.valueOf(filterFunction.getFunctionName().toUpperCase());
     List<ExpressionContext> operands = filterFunction.getArguments();
     int numOperands = operands.size();
     switch (filterKind) {
-      case AND:
+      case AND: {
         List<FilterContext> children = new ArrayList<>(numOperands);
         for (ExpressionContext operand : operands) {
-          children.add(getFilter(operand));
+          FilterContext filter = getFilter(operand);
+          if (!filter.isConstant()) {
+            children.add(filter);
+          } else {
+            if (filter.isConstantFalse()) {
+              return FilterContext.CONSTANT_FALSE;
+            }
+          }
         }
-        return new FilterContext(FilterContext.Type.AND, children, null);
-      case OR:
-        children = new ArrayList<>(numOperands);
+        int numChildren = children.size();
+        if (numChildren == 0) {
+          return FilterContext.CONSTANT_TRUE;
+        } else if (numChildren == 1) {
+          return children.get(0);
+        } else {
+          return FilterContext.forAnd(children);
+        }
+      }
+      case OR: {
+        List<FilterContext> children = new ArrayList<>(numOperands);
         for (ExpressionContext operand : operands) {
-          children.add(getFilter(operand));
+          FilterContext filter = getFilter(operand);
+          if (!filter.isConstant()) {
+            children.add(filter);
+          } else {
+            if (filter.isConstantTrue()) {
+              return FilterContext.CONSTANT_TRUE;
+            }
+          }
         }
-        return new FilterContext(FilterContext.Type.OR, children, null);
-      case NOT:
+        int numChildren = children.size();
+        if (numChildren == 0) {
+          return FilterContext.CONSTANT_FALSE;
+        } else if (numChildren == 1) {
+          return children.get(0);
+        } else {
+          return FilterContext.forOr(children);
+        }
+      }
+      case NOT: {
         assert numOperands == 1;
-        return new FilterContext(FilterContext.Type.NOT,
-            new ArrayList<>(Collections.singletonList(getFilter(operands.get(0)))), null);
+        FilterContext filter = getFilter(operands.get(0));
+        if (!filter.isConstant()) {
+          return FilterContext.forNot(filter);
+        } else {
+          return filter.isConstantTrue() ? FilterContext.CONSTANT_FALSE : FilterContext.CONSTANT_TRUE;
+        }
+      }
       case EQUALS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new EqPredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new EqPredicate(operands.get(0), getStringValue(operands.get(1))));
       case NOT_EQUALS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new NotEqPredicate(operands.get(0), getStringValue(operands.get(1))));
-      case IN:
+        return FilterContext.forPredicate(new NotEqPredicate(operands.get(0), getStringValue(operands.get(1))));
+      case IN: {
         List<String> values = new ArrayList<>(numOperands - 1);
         for (int i = 1; i < numOperands; i++) {
           values.add(getStringValue(operands.get(i)));
         }
-        return new FilterContext(FilterContext.Type.PREDICATE, null, new InPredicate(operands.get(0), values));
-      case NOT_IN:
-        values = new ArrayList<>(numOperands - 1);
+        return FilterContext.forPredicate(new InPredicate(operands.get(0), values));
+      }
+      case NOT_IN: {
+        List<String> values = new ArrayList<>(numOperands - 1);
         for (int i = 1; i < numOperands; i++) {
           values.add(getStringValue(operands.get(i)));
         }
-        return new FilterContext(FilterContext.Type.PREDICATE, null, new NotInPredicate(operands.get(0), values));
+        return FilterContext.forPredicate(new NotInPredicate(operands.get(0), values));
+      }
       case GREATER_THAN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(operands.get(0), false, getStringValue(operands.get(1)), false,
                 RangePredicate.UNBOUNDED));
       case GREATER_THAN_OR_EQUAL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(operands.get(0), true, getStringValue(operands.get(1)), false,
                 RangePredicate.UNBOUNDED));
       case LESS_THAN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new RangePredicate(operands.get(0), false, RangePredicate.UNBOUNDED, false,
-                getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new RangePredicate(operands.get(0), false, RangePredicate.UNBOUNDED, false,
+            getStringValue(operands.get(1))));
       case LESS_THAN_OR_EQUAL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new RangePredicate(operands.get(0), false, RangePredicate.UNBOUNDED, true,
-                getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new RangePredicate(operands.get(0), false, RangePredicate.UNBOUNDED, true,
+            getStringValue(operands.get(1))));
       case BETWEEN:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
+        return FilterContext.forPredicate(
             new RangePredicate(operands.get(0), true, getStringValue(operands.get(1)), true,
                 getStringValue(operands.get(2))));
       case RANGE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new RangePredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new RangePredicate(operands.get(0), getStringValue(operands.get(1))));
       case REGEXP_LIKE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new RegexpLikePredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new RegexpLikePredicate(operands.get(0), getStringValue(operands.get(1))));
       case LIKE:
-        return new FilterContext(FilterContext.Type.PREDICATE, null, new RegexpLikePredicate(operands.get(0),
+        return FilterContext.forPredicate(new RegexpLikePredicate(operands.get(0),
             RegexpPatternConverterUtils.likeToRegexpLike(getStringValue(operands.get(1)))));
       case TEXT_CONTAINS:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new TextContainsPredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new TextContainsPredicate(operands.get(0), getStringValue(operands.get(1))));
       case TEXT_MATCH:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new TextMatchPredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new TextMatchPredicate(operands.get(0), getStringValue(operands.get(1))));
       case JSON_MATCH:
-        return new FilterContext(FilterContext.Type.PREDICATE, null,
-            new JsonMatchPredicate(operands.get(0), getStringValue(operands.get(1))));
+        return FilterContext.forPredicate(new JsonMatchPredicate(operands.get(0), getStringValue(operands.get(1))));
       case IS_NULL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null, new IsNullPredicate(operands.get(0)));
+        return FilterContext.forPredicate(new IsNullPredicate(operands.get(0)));
       case IS_NOT_NULL:
-        return new FilterContext(FilterContext.Type.PREDICATE, null, new IsNotNullPredicate(operands.get(0)));
+        return FilterContext.forPredicate(new IsNotNullPredicate(operands.get(0)));
       default:
         throw new IllegalStateException();
     }
@@ -354,7 +408,7 @@ public class RequestContextUtils {
   //       literal context doesn't support float, and we cannot differentiate explicit string literal and literal
   //       without explicit type, so we always convert the literal into string.
   private static String getStringValue(ExpressionContext expressionContext) {
-    if(expressionContext.getType() != ExpressionContext.Type.LITERAL){
+    if (expressionContext.getType() != ExpressionContext.Type.LITERAL) {
       throw new BadQueryRequestException(
           "Pinot does not support column or function on the right-hand side of the predicate");
     }
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
index 4834866c51..412c1d2421 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/io/InputManager.java
@@ -35,6 +35,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.commons.lang3.tuple.Triple;
 import org.apache.pinot.common.request.BrokerRequest;
 import org.apache.pinot.common.request.PinotQuery;
+import org.apache.pinot.common.request.context.FilterContext;
 import org.apache.pinot.controller.recommender.exceptions.InvalidInputException;
 import org.apache.pinot.controller.recommender.io.metadata.FieldMetadata;
 import org.apache.pinot.controller.recommender.io.metadata.SchemaWithMetaData;
@@ -177,10 +178,11 @@ public class InputManager {
 
         // Flag the queries having in filter columns not appear in schema
         // to exclude user input like select i from tableName where a = xyz and t > 500
-        Set<String> filterColumns = new HashSet<>();
-        if (queryContext.getFilter() != null) {
+        FilterContext filter = queryContext.getFilter();
+        if (filter != null && !filter.isConstant()) {
+          Set<String> filterColumns = new HashSet<>();
           // get in filter column names, excluding literals, etc
-          queryContext.getFilter().getColumns(filterColumns);
+          filter.getColumns(filterColumns);
           // remove those appear in schema
           filterColumns.removeAll(_colNameToIntMap.keySet());
           // flag if there are columns left
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/BloomFilterRule.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/BloomFilterRule.java
index 5a9de70e5d..2ac5daa22c 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/BloomFilterRule.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/BloomFilterRule.java
@@ -87,12 +87,13 @@ public class BloomFilterRule extends AbstractRule {
   }
 
   public FixedLenBitset parseQuery(QueryContext queryContext) {
-    if (queryContext.getFilter() == null) {
+    FilterContext filter = queryContext.getFilter();
+    if (filter == null || filter.isConstant()) {
       return FixedLenBitset.IMMUTABLE_EMPTY_SET;
     }
 
-    LOGGER.trace("Parsing Where Clause: {}", queryContext.getFilter().toString());
-    return parsePredicateList(queryContext.getFilter());
+    LOGGER.trace("Parsing Where Clause: {}", filter);
+    return parsePredicateList(filter);
   }
 
   /**
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/FlagQueryRule.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/FlagQueryRule.java
index 8995f3857e..60533be596 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/FlagQueryRule.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/FlagQueryRule.java
@@ -21,6 +21,7 @@ package org.apache.pinot.controller.recommender.rules.impl;
 
 import java.util.HashSet;
 import java.util.Set;
+import org.apache.pinot.common.request.context.FilterContext;
 import org.apache.pinot.controller.recommender.io.ConfigManager;
 import org.apache.pinot.controller.recommender.io.InputManager;
 import org.apache.pinot.controller.recommender.rules.AbstractRule;
@@ -59,12 +60,13 @@ public class FlagQueryRule extends AbstractRule {
         _output.getFlaggedQueries().add(query, WARNING_TOO_LONG_LIMIT);
       }
 
-      if (queryContext.getFilter() == null) {
+      FilterContext filter = queryContext.getFilter();
+      if (filter == null || filter.isConstant()) {
         //Flag the queries that are not using any filters.
         _output.getFlaggedQueries().add(query, WARNING_NO_FILTERING);
       } else { //Flag the queries that are not using any time filters.
         Set<String> usedCols = new HashSet<>();
-        queryContext.getFilter().getColumns(usedCols);
+        filter.getColumns(usedCols);
         Set<String> timeCols = _input.getTimeColumns();
         if (!timeCols.isEmpty()) {
           usedCols.retainAll(timeCols);
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/NoDictionaryOnHeapDictionaryJointRule.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/NoDictionaryOnHeapDictionaryJointRule.java
index 6b07f56254..03d2acf9bf 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/NoDictionaryOnHeapDictionaryJointRule.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/NoDictionaryOnHeapDictionaryJointRule.java
@@ -197,8 +197,9 @@ public class NoDictionaryOnHeapDictionaryJointRule extends AbstractRule {
       });
     }
 
-    if (queryContext.getFilter() != null) {
-      fixedLenBitsetFilterGroupBy.union(parsePredicateList(queryContext.getFilter()));
+    FilterContext filter = queryContext.getFilter();
+    if (filter != null && !filter.isConstant()) {
+      fixedLenBitsetFilterGroupBy.union(parsePredicateList(filter));
     }
 
     for (Integer colId : fixedLenBitsetFilterGroupBy.getOffsets()) {
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/PinotTablePartitionRule.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/PinotTablePartitionRule.java
index ca879d735c..609c91cf86 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/PinotTablePartitionRule.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/PinotTablePartitionRule.java
@@ -184,12 +184,13 @@ public class PinotTablePartitionRule extends AbstractRule {
    * See PartitionSegmentPruner
    */
   public FixedLenBitset parseQuery(QueryContext queryContext) {
-    if (queryContext.getFilter() == null) {
+    FilterContext filter = queryContext.getFilter();
+    if (filter == null || filter.isConstant()) {
       return FixedLenBitset.IMMUTABLE_EMPTY_SET;
     }
 
-    LOGGER.trace("Parsing Where Clause: {}", queryContext.getFilter().toString());
-    return parsePredicateList(queryContext.getFilter());
+    LOGGER.trace("Parsing Where Clause: {}", filter);
+    return parsePredicateList(filter);
   }
 
   @Nullable
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/RangeIndexRule.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/RangeIndexRule.java
index 17424923cb..360dae4e68 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/RangeIndexRule.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/impl/RangeIndexRule.java
@@ -79,11 +79,12 @@ public class RangeIndexRule extends AbstractRule {
   }
 
   public FixedLenBitset parseQuery(QueryContext queryContext) {
-    if (queryContext.getFilter() == null) {
+    FilterContext filter = queryContext.getFilter();
+    if (filter == null || filter.isConstant()) {
       return FixedLenBitset.IMMUTABLE_EMPTY_SET;
     }
 
-    return parsePredicateList(queryContext.getFilter());
+    return parsePredicateList(filter);
   }
 
   /**
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/utils/QueryInvertedSortedIndexRecommender.java b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/utils/QueryInvertedSortedIndexRecommender.java
index 749b137144..f0eb891a13 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/utils/QueryInvertedSortedIndexRecommender.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/recommender/rules/utils/QueryInvertedSortedIndexRecommender.java
@@ -87,12 +87,13 @@ public class QueryInvertedSortedIndexRecommender {
    * meaning that at most one candidate (PredicateParseResult) in the list can contribute to the global recommendation.
    */
   public List<List<PredicateParseResult>> parseQuery(QueryContext queryContext, double queryWeight) {
-    if (queryContext.getFilter() == null) {
+    FilterContext filter = queryContext.getFilter();
+    if (filter == null || filter.isConstant()) {
       return EMPTY_PARSE_RESULT;
     }
 
-    LOGGER.trace("Parsing Where Clause: {}", queryContext.getFilter().toString());
-    return parseTopLevel(queryContext.getFilter(), queryWeight);
+    LOGGER.trace("Parsing Where Clause: {}", filter);
+    return parseTopLevel(filter, queryWeight);
   }
 
   /**
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctCountThetaSketchAggregationFunction.java b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctCountThetaSketchAggregationFunction.java
index c6a57b373f..f3a9adfda6 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctCountThetaSketchAggregationFunction.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/aggregation/function/DistinctCountThetaSketchAggregationFunction.java
@@ -132,6 +132,7 @@ public class DistinctCountThetaSketchAggregationFunction
                 + "(filter expression)");
         FilterContext filter = RequestContextUtils.getFilter(
             CalciteSqlParser.compileToExpression(filterExpression.getLiteral().getStringValue()));
+        Preconditions.checkArgument(!filter.isConstant(), "Filter must not be constant: %s", filter);
         // NOTE: Collect expressions before constructing the FilterInfo so that expressionIndexMap always include the
         //       expressions in the filter.
         collectExpressions(filter, _inputExpressions, expressionIndexMap);
@@ -146,7 +147,6 @@ public class DistinctCountThetaSketchAggregationFunction
       Expression expr = CalciteSqlParser.compileToExpression(postAggregationExpression.getLiteral().getStringValue());
       _postAggregationExpression = RequestContextUtils.getExpression(expr);
 
-
       // Validate the post-aggregation expression
       _includeDefaultSketch = validatePostAggregationExpression(_postAggregationExpression, _filterEvaluators.size());
     }
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java b/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
index 4c3248e527..17ce5ae159 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/executor/ServerQueryExecutorV1Impl.java
@@ -20,6 +20,7 @@ package org.apache.pinot.core.query.executor;
 
 import com.google.common.base.Preconditions;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -349,12 +350,18 @@ public class ServerQueryExecutorV1Impl implements QueryExecutor {
       numTotalDocs += indexSegment.getSegmentMetadata().getTotalDocs();
     }
 
-    TimerContext.Timer segmentPruneTimer = timerContext.startNewPhaseTimer(ServerQueryPhase.SEGMENT_PRUNING);
+    List<IndexSegment> selectedSegments;
+    SegmentPrunerStatistics prunerStats = null;
+    if ((queryContext.getFilter() != null && queryContext.getFilter().isConstantFalse()) || (
+        queryContext.getHavingFilter() != null && queryContext.getHavingFilter().isConstantFalse())) {
+      selectedSegments = Collections.emptyList();
+    } else {
+      TimerContext.Timer segmentPruneTimer = timerContext.startNewPhaseTimer(ServerQueryPhase.SEGMENT_PRUNING);
+      prunerStats = new SegmentPrunerStatistics();
+      selectedSegments = _segmentPrunerService.prune(indexSegments, queryContext, prunerStats, executorService);
+      segmentPruneTimer.stopAndRecord();
+    }
     int numTotalSegments = indexSegments.size();
-    SegmentPrunerStatistics prunerStats = new SegmentPrunerStatistics();
-    List<IndexSegment> selectedSegments =
-        _segmentPrunerService.prune(indexSegments, queryContext, prunerStats, executorService);
-    segmentPruneTimer.stopAndRecord();
     int numSelectedSegments = selectedSegments.size();
     LOGGER.debug("Matched {} segments after pruning", numSelectedSegments);
     InstanceResponseBlock instanceResponse;
@@ -383,7 +390,9 @@ public class ServerQueryExecutorV1Impl implements QueryExecutor {
     // Set the number of pruned segments. This count does not include the segments which returned empty filters
     int prunedSegments = numTotalSegments - numSelectedSegments;
     instanceResponse.addMetadata(MetadataKey.NUM_SEGMENTS_PRUNED_BY_SERVER.getName(), String.valueOf(prunedSegments));
-    addPrunerStats(instanceResponse, prunerStats);
+    if (prunerStats != null) {
+      addPrunerStats(instanceResponse, prunerStats);
+    }
 
     return instanceResponse;
   }
@@ -512,7 +521,7 @@ public class ServerQueryExecutorV1Impl implements QueryExecutor {
       ExecutorService executorService)
       throws Exception {
     FilterContext filter = queryContext.getFilter();
-    if (filter != null) {
+    if (filter != null && !filter.isConstant()) {
       handleSubquery(filter, indexSegments, timerContext, executorService, queryContext.getEndTimeMs());
     }
   }
diff --git a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java
index 4de58610de..47a89be814 100644
--- a/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/query/request/context/utils/QueryContextConverterUtils.java
@@ -96,6 +96,10 @@ public class QueryContextConverterUtils {
     Expression filterExpression = pinotQuery.getFilterExpression();
     if (filterExpression != null) {
       filter = RequestContextUtils.getFilter(filterExpression);
+      // Remove the filter if it is always true
+      if (filter.isConstantTrue()) {
+        filter = null;
+      }
     }
 
     // GROUP BY
@@ -135,6 +139,10 @@ public class QueryContextConverterUtils {
     Expression havingExpression = pinotQuery.getHavingExpression();
     if (havingExpression != null) {
       havingFilter = RequestContextUtils.getFilter(havingExpression);
+      // Remove the filter if it is always true
+      if (havingFilter.isConstantTrue()) {
+        havingFilter = null;
+      }
     }
 
     // EXPRESSION OVERRIDE HINTS
diff --git a/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java b/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java
index 866282478e..efeb7ac071 100644
--- a/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/core/query/request/context/utils/BrokerRequestToQueryContextConverterTest.java
@@ -294,17 +294,17 @@ public class BrokerRequestToQueryContextConverterTest {
       assertEquals(filter.getType(), FilterContext.Type.AND);
       List<FilterContext> children = filter.getChildren();
       assertEquals(children.size(), 2);
-      assertEquals(children.get(0), new FilterContext(FilterContext.Type.PREDICATE, null,
+      assertEquals(children.get(0), FilterContext.forPredicate(
           new RangePredicate(ExpressionContext.forIdentifier("foo"), false, "15", false, "*")));
       FilterContext orFilter = children.get(1);
       assertEquals(orFilter.getType(), FilterContext.Type.OR);
       assertEquals(orFilter.getChildren().size(), 2);
-      assertEquals(orFilter.getChildren().get(0), new FilterContext(FilterContext.Type.PREDICATE, null,
-          new RangePredicate(ExpressionContext.forFunction(new FunctionContext(FunctionContext.Type.TRANSFORM, "div",
+      assertEquals(orFilter.getChildren().get(0), FilterContext.forPredicate(new RangePredicate(
+          ExpressionContext.forFunction(new FunctionContext(FunctionContext.Type.TRANSFORM, "div",
               Arrays.asList(ExpressionContext.forIdentifier("bar"), ExpressionContext.forIdentifier("foo")))), true,
-              "10", true, "20")));
-      assertEquals(orFilter.getChildren().get(1), new FilterContext(FilterContext.Type.PREDICATE, null,
-          new TextMatchPredicate(ExpressionContext.forIdentifier("foobar"), "potato")));
+          "10", true, "20")));
+      assertEquals(orFilter.getChildren().get(1),
+          FilterContext.forPredicate(new TextMatchPredicate(ExpressionContext.forIdentifier("foobar"), "potato")));
       assertEquals(filter.toString(),
           "(foo > '15' AND (div(bar,foo) BETWEEN '10' AND '20' OR text_match(foobar,'potato')))");
       assertNull(queryContext.getGroupByExpressions());
@@ -340,7 +340,7 @@ public class BrokerRequestToQueryContextConverterTest {
       assertEquals(aliasList.get(1), "b");
       FilterContext filter = queryContext.getFilter();
       assertNotNull(filter);
-      assertEquals(filter, new FilterContext(FilterContext.Type.PREDICATE, null,
+      assertEquals(filter, FilterContext.forPredicate(
           new InPredicate(ExpressionContext.forIdentifier("bar"), Arrays.asList("5", "10", "15"))));
       assertEquals(filter.toString(), "bar IN ('5','10','15')");
       List<ExpressionContext> groupByExpressions = queryContext.getGroupByExpressions();
@@ -388,8 +388,8 @@ public class BrokerRequestToQueryContextConverterTest {
       assertNull(queryContext.getOrderByExpressions());
       FilterContext havingFilter = queryContext.getHavingFilter();
       assertNotNull(havingFilter);
-      assertEquals(havingFilter, new FilterContext(FilterContext.Type.PREDICATE, null, new InPredicate(
-          ExpressionContext.forFunction(new FunctionContext(FunctionContext.Type.AGGREGATION, "sum",
+      assertEquals(havingFilter, FilterContext.forPredicate(new InPredicate(ExpressionContext.forFunction(
+          new FunctionContext(FunctionContext.Type.AGGREGATION, "sum",
               Collections.singletonList(ExpressionContext.forIdentifier("foo")))), Arrays.asList("5", "10", "15"))));
       assertEquals(havingFilter.toString(), "sum(foo) IN ('5','10','15')");
       assertEquals(queryContext.getLimit(), 10);
@@ -658,7 +658,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testDeduplicateOrderByExpressions() {
+  public void testDeduplicateOrderByExpressions() {
     String query = "SELECT name FROM employees ORDER BY name DESC NULLS LAST, name ASC";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -668,7 +668,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testRemoveOrderByFunctions() {
+  public void testRemoveOrderByFunctions() {
     String query = "SELECT A FROM testTable ORDER BY datetrunc(A) DESC NULLS LAST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -684,7 +684,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByDefault() {
+  public void testOrderByDefault() {
     String query = "SELECT A FROM testTable ORDER BY A";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -698,7 +698,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByNullsLast() {
+  public void testOrderByNullsLast() {
     String query = "SELECT A FROM testTable ORDER BY A NULLS LAST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -712,7 +712,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByNullsFirst() {
+  public void testOrderByNullsFirst() {
     String query = "SELECT A FROM testTable ORDER BY A NULLS FIRST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -726,7 +726,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByAscNullsFirst() {
+  public void testOrderByAscNullsFirst() {
     String query = "SELECT A FROM testTable ORDER BY A ASC NULLS FIRST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -740,7 +740,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByAscNullsLast() {
+  public void testOrderByAscNullsLast() {
     String query = "SELECT A FROM testTable ORDER BY A ASC NULLS LAST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -754,7 +754,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByDescNullsFirst() {
+  public void testOrderByDescNullsFirst() {
     String query = "SELECT A FROM testTable ORDER BY A DESC NULLS FIRST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -768,7 +768,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testOrderByDescNullsLast() {
+  public void testOrderByDescNullsLast() {
     String query = "SELECT A FROM testTable ORDER BY A DESC NULLS LAST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -782,7 +782,7 @@ public class BrokerRequestToQueryContextConverterTest {
   }
 
   @Test
-  void testDistinctOrderByNullsLast() {
+  public void testDistinctOrderByNullsLast() {
     String query = "SELECT DISTINCT A FROM testTable ORDER BY A NULLS LAST";
 
     QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
@@ -794,4 +794,55 @@ public class BrokerRequestToQueryContextConverterTest {
     assertTrue(orderByExpressionContext.isAsc());
     assertTrue(orderByExpressionContext.isNullsLast());
   }
+
+  @Test
+  public void testConstantFilter() {
+    String query = "SELECT * FROM testTable WHERE true";
+    QueryContext queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+
+    query = "SELECT * FROM testTable WHERE false";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE 'true'";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+
+    query = "SELECT * FROM testTable WHERE 'false'";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE 1 = 1";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+
+    query = "SELECT * FROM testTable WHERE 1 = 0";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE 1 = 1 AND 2 = 2";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+
+    query = "SELECT * FROM testTable WHERE 1 = 1 AND 2 = 3";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE 1 = 1 OR 2 = 3";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+
+    query = "SELECT * FROM testTable WHERE 1 = 0 OR 2 = 3";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE NOT 1 = 1";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertSame(queryContext.getFilter(), FilterContext.CONSTANT_FALSE);
+
+    query = "SELECT * FROM testTable WHERE NOT 1 = 0";
+    queryContext = QueryContextConverterUtils.getQueryContext(query);
+    assertNull(queryContext.getFilter());
+  }
 }
diff --git a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/json/MutableJsonIndexImpl.java b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/json/MutableJsonIndexImpl.java
index afa73f0a3a..46e7798204 100644
--- a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/json/MutableJsonIndexImpl.java
+++ b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/realtime/impl/json/MutableJsonIndexImpl.java
@@ -120,6 +120,7 @@ public class MutableJsonIndexImpl implements MutableJsonIndex {
     FilterContext filter;
     try {
       filter = RequestContextUtils.getFilter(CalciteSqlParser.compileToExpression(filterString));
+      Preconditions.checkArgument(!filter.isConstant());
     } catch (Exception e) {
       throw new BadQueryRequestException("Invalid json match filter: " + filterString);
     }
diff --git a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/json/ImmutableJsonIndexReader.java b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/json/ImmutableJsonIndexReader.java
index 757053e323..ac4a24d56d 100644
--- a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/json/ImmutableJsonIndexReader.java
+++ b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/json/ImmutableJsonIndexReader.java
@@ -86,6 +86,7 @@ public class ImmutableJsonIndexReader implements JsonIndexReader {
     FilterContext filter;
     try {
       filter = RequestContextUtils.getFilter(CalciteSqlParser.compileToExpression(filterString));
+      Preconditions.checkArgument(!filter.isConstant());
     } catch (Exception e) {
       throw new BadQueryRequestException("Invalid json match filter: " + filterString);
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org