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 e84f3f5667 ensure inverse And/OrFilterOperator implementations match 
the query (#13199)
e84f3f5667 is described below

commit e84f3f5667d5e78db60f5b09de61e89dae532c7e
Author: Christopher Peck <[email protected]>
AuthorDate: Fri May 24 20:53:09 2024 -0700

    ensure inverse And/OrFilterOperator implementations match the query (#13199)
---
 .../core/operator/filter/AndFilterOperator.java    | 29 ++++++--
 .../core/operator/filter/BaseFilterOperator.java   | 18 +++--
 .../core/operator/filter/OrFilterOperator.java     | 30 ++++++--
 .../core/operator/filter/TestFilterOperator.java   | 11 +++
 .../operator/filter/AndFilterOperatorTest.java     | 42 ++++++++++++
 .../operator/filter/BaseFilterOperatorTest.java    | 79 ++++++++++++++++++++++
 .../core/operator/filter/OrFilterOperatorTest.java | 43 ++++++++++++
 7 files changed, 237 insertions(+), 15 deletions(-)

diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/AndFilterOperator.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/AndFilterOperator.java
index 93c79871fa..94545d8889 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/AndFilterOperator.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/AndFilterOperator.java
@@ -19,13 +19,16 @@
 package org.apache.pinot.core.operator.filter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
 import org.apache.pinot.core.common.BlockDocIdSet;
 import org.apache.pinot.core.common.Operator;
 import org.apache.pinot.core.operator.docidsets.AndDocIdSet;
+import org.apache.pinot.core.operator.docidsets.EmptyDocIdSet;
 import org.apache.pinot.core.operator.docidsets.MatchAllDocIdSet;
+import org.apache.pinot.core.operator.docidsets.NotDocIdSet;
 import org.apache.pinot.core.operator.docidsets.OrDocIdSet;
 import org.apache.pinot.spi.trace.Tracing;
 import org.roaringbitmap.buffer.BufferFastAggregation;
@@ -59,13 +62,29 @@ public class AndFilterOperator extends BaseFilterOperator {
   protected BlockDocIdSet getFalses() {
     List<BlockDocIdSet> blockDocIdSets = new 
ArrayList<>(_filterOperators.size());
     for (BaseFilterOperator filterOperator : _filterOperators) {
-      if (filterOperator.isResultEmpty()) {
-        blockDocIdSets.add(new MatchAllDocIdSet(_numDocs));
-      } else {
-        blockDocIdSets.add(filterOperator.getFalses());
+      BlockDocIdSet trues = filterOperator.getTrues();
+      if (trues instanceof EmptyDocIdSet) {
+        return new MatchAllDocIdSet(_numDocs);
       }
+      if (trues instanceof MatchAllDocIdSet) {
+        continue;
+      }
+      if (_nullHandlingEnabled) {
+        BlockDocIdSet nulls = filterOperator.getNulls();
+        if (!(nulls instanceof EmptyDocIdSet)) {
+          blockDocIdSets.add(new OrDocIdSet(Arrays.asList(trues, nulls), 
_numDocs));
+          continue;
+        }
+      }
+      blockDocIdSets.add(trues);
+    }
+    if (blockDocIdSets.isEmpty()) {
+      return EmptyDocIdSet.getInstance();
+    }
+    if (blockDocIdSets.size() == 1) {
+      return new NotDocIdSet(blockDocIdSets.get(0), _numDocs);
     }
-    return new OrDocIdSet(blockDocIdSets, _numDocs);
+    return new NotDocIdSet(new AndDocIdSet(blockDocIdSets, _queryOptions), 
_numDocs);
   }
 
   @Override
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BaseFilterOperator.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BaseFilterOperator.java
index 75140d73c4..7acbd6ed7c 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BaseFilterOperator.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BaseFilterOperator.java
@@ -23,6 +23,7 @@ import org.apache.pinot.core.common.BlockDocIdSet;
 import org.apache.pinot.core.operator.BaseOperator;
 import org.apache.pinot.core.operator.blocks.FilterBlock;
 import org.apache.pinot.core.operator.docidsets.EmptyDocIdSet;
+import org.apache.pinot.core.operator.docidsets.MatchAllDocIdSet;
 import org.apache.pinot.core.operator.docidsets.NotDocIdSet;
 import org.apache.pinot.core.operator.docidsets.OrDocIdSet;
 
@@ -102,11 +103,20 @@ public abstract class BaseFilterOperator extends 
BaseOperator<FilterBlock> {
    * @return document IDs in which the predicate evaluates to false.
    */
   protected BlockDocIdSet getFalses() {
+    BlockDocIdSet trues = getTrues();
+    if (trues instanceof MatchAllDocIdSet) {
+      return EmptyDocIdSet.getInstance();
+    }
     if (_nullHandlingEnabled) {
-      return new NotDocIdSet(new OrDocIdSet(Arrays.asList(getTrues(), 
getNulls()), _numDocs),
-          _numDocs);
-    } else {
-      return new NotDocIdSet(getTrues(), _numDocs);
+      BlockDocIdSet nulls = getNulls();
+      if (!(nulls instanceof EmptyDocIdSet)) {
+        return new NotDocIdSet(new OrDocIdSet(Arrays.asList(trues, nulls), 
_numDocs),
+            _numDocs);
+      }
+    }
+    if (trues instanceof EmptyDocIdSet) {
+      return new MatchAllDocIdSet(_numDocs);
     }
+    return new NotDocIdSet(trues, _numDocs);
   }
 }
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/OrFilterOperator.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/OrFilterOperator.java
index 5b99d58353..9f8477f96d 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/OrFilterOperator.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/OrFilterOperator.java
@@ -19,13 +19,15 @@
 package org.apache.pinot.core.operator.filter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nullable;
 import org.apache.pinot.core.common.BlockDocIdSet;
 import org.apache.pinot.core.common.Operator;
-import org.apache.pinot.core.operator.docidsets.AndDocIdSet;
+import org.apache.pinot.core.operator.docidsets.EmptyDocIdSet;
 import org.apache.pinot.core.operator.docidsets.MatchAllDocIdSet;
+import org.apache.pinot.core.operator.docidsets.NotDocIdSet;
 import org.apache.pinot.core.operator.docidsets.OrDocIdSet;
 import org.apache.pinot.spi.trace.Tracing;
 import org.roaringbitmap.buffer.BufferFastAggregation;
@@ -59,13 +61,29 @@ public class OrFilterOperator extends BaseFilterOperator {
   protected BlockDocIdSet getFalses() {
     List<BlockDocIdSet> blockDocIdSets = new 
ArrayList<>(_filterOperators.size());
     for (BaseFilterOperator filterOperator : _filterOperators) {
-      if (filterOperator.isResultEmpty()) {
-        blockDocIdSets.add(new MatchAllDocIdSet(_numDocs));
-      } else {
-        blockDocIdSets.add(filterOperator.getFalses());
+      BlockDocIdSet trues = filterOperator.getTrues();
+      if (trues instanceof MatchAllDocIdSet) {
+        return EmptyDocIdSet.getInstance();
       }
+      if (trues instanceof EmptyDocIdSet) {
+        continue;
+      }
+      if (_nullHandlingEnabled) {
+        BlockDocIdSet nulls = filterOperator.getNulls();
+        if (!(nulls instanceof EmptyDocIdSet)) {
+          blockDocIdSets.add(new OrDocIdSet(Arrays.asList(trues, nulls), 
_numDocs));
+          continue;
+        }
+      }
+      blockDocIdSets.add(trues);
+    }
+    if (blockDocIdSets.isEmpty()) {
+      return new MatchAllDocIdSet(_numDocs);
+    }
+    if (blockDocIdSets.size() == 1) {
+      return new NotDocIdSet(blockDocIdSets.get(0), _numDocs);
     }
-    return new AndDocIdSet(blockDocIdSets, _queryOptions);
+    return new NotDocIdSet(new OrDocIdSet(blockDocIdSets, _numDocs), _numDocs);
   }
 
   @Override
diff --git 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/TestFilterOperator.java
 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/TestFilterOperator.java
index 3aff520c87..270e4cee39 100644
--- 
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/TestFilterOperator.java
+++ 
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/TestFilterOperator.java
@@ -23,6 +23,8 @@ import java.util.List;
 import org.apache.pinot.core.common.BlockDocIdIterator;
 import org.apache.pinot.core.common.BlockDocIdSet;
 import org.apache.pinot.core.common.Operator;
+import org.apache.pinot.core.operator.docidsets.EmptyDocIdSet;
+import org.apache.pinot.core.operator.docidsets.MatchAllDocIdSet;
 import org.apache.pinot.segment.spi.Constants;
 
 
@@ -56,11 +58,20 @@ public class TestFilterOperator extends BaseFilterOperator {
 
   @Override
   protected BlockDocIdSet getTrues() {
+    if (_trueDocIds.length == _numDocs) {
+      return new MatchAllDocIdSet(_numDocs);
+    }
+    if (_trueDocIds.length == 0) {
+      return EmptyDocIdSet.getInstance();
+    }
     return new TestBlockDocIdSet(_trueDocIds);
   }
 
   @Override
   protected BlockDocIdSet getNulls() {
+    if (_nullDocIds.length == 0) {
+      return EmptyDocIdSet.getInstance();
+    }
     return new TestBlockDocIdSet(_nullDocIds);
   }
 
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/AndFilterOperatorTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/AndFilterOperatorTest.java
index fa7320969a..230a3ead55 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/AndFilterOperatorTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/AndFilterOperatorTest.java
@@ -178,6 +178,22 @@ public class AndFilterOperatorTest {
     Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getFalses()), 
ImmutableList.of(0, 7, 8, 9));
   }
 
+  @Test
+  public void testAndWithNullHandlingDisabled() {
+    int numDocs = 4;
+    int[] docIds1 = new int[]{0, 3};
+    int[] docIds2 = new int[]{0, 1};
+    int[] nullDocIds1 = new int[]{};
+    int[] nullDocIds2 = new int[]{};
+
+    AndFilterOperator andFilterOperator = new AndFilterOperator(
+        Arrays.asList(new TestFilterOperator(docIds1, nullDocIds1, numDocs),
+            new TestFilterOperator(docIds2, nullDocIds2, numDocs)), null, 
numDocs, false);
+
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getTrues()), 
ImmutableList.of(0));
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getFalses()), 
ImmutableList.of(1, 2, 3));
+  }
+
   @Test
   public void testAndWithNullOneFilterIsEmpty() {
     int numDocs = 10;
@@ -192,4 +208,30 @@ public class AndFilterOperatorTest {
     Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getFalses()),
         ImmutableList.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
   }
+
+  @Test
+  public void testAndWithNullOneFilterMatchesAll() {
+    int numDocs = 10;
+    int[] docIds1 = new int[]{1, 2, 3};
+    int[] nullDocIds1 = new int[]{4, 5, 6};
+
+    AndFilterOperator andFilterOperator = new AndFilterOperator(
+        Arrays.asList(new TestFilterOperator(docIds1, nullDocIds1, numDocs), 
new MatchAllFilterOperator(numDocs)), null,
+        numDocs, true);
+
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getTrues()), 
ImmutableList.of(1, 2, 3));
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getFalses()), 
ImmutableList.of(0, 7, 8, 9));
+  }
+
+  @Test
+  public void testAndWithAllMatchesAll() {
+    int numDocs = 10;
+    AndFilterOperator andFilterOperator =
+        new AndFilterOperator(Arrays.asList(new 
MatchAllFilterOperator(numDocs), new MatchAllFilterOperator(numDocs)),
+            null, numDocs, true);
+
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getTrues()),
+        ImmutableList.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+    Assert.assertEquals(TestUtils.getDocIds(andFilterOperator.getFalses()), 
Collections.emptyList());
+  }
 }
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BaseFilterOperatorTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BaseFilterOperatorTest.java
new file mode 100644
index 0000000000..4d9ecf5cc4
--- /dev/null
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BaseFilterOperatorTest.java
@@ -0,0 +1,79 @@
+/**
+ * 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.core.operator.filter;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collections;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+public class BaseFilterOperatorTest {
+
+  @Test
+  public void testBaseWithFalses() {
+    int numDocs = 10;
+    int[] docIds = new int[]{0, 1, 2, 3};
+    TestFilterOperator testFilterOperator = new TestFilterOperator(docIds, 
numDocs);
+
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getTrues()), 
ImmutableList.of(0, 1, 2, 3));
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getFalses()), 
ImmutableList.of(4, 5, 6, 7, 8, 9));
+  }
+
+  @Test
+  public void testBaseWithNullHandling() {
+    int numDocs = 10;
+    int[] docIds = new int[]{0, 1, 2, 3};
+    int[] nullDocIds = new int[]{4, 5, 6, 7, 8, 9};
+    TestFilterOperator testFilterOperator = new TestFilterOperator(docIds, 
nullDocIds, numDocs);
+
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getTrues()), 
ImmutableList.of(0, 1, 2, 3));
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getFalses()), 
Collections.emptyList());
+  }
+
+  @Test
+  public void testBaseWithAllTrue() {
+    int numDocs = 10;
+    int[] docIds = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    TestFilterOperator testFilterOperator = new TestFilterOperator(docIds, 
numDocs);
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getTrues()),
+        ImmutableList.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getFalses()), 
Collections.emptyList());
+  }
+
+  @Test
+  public void testBaseWithAllFalse() {
+    int numDocs = 10;
+    int[] docIds = new int[]{};
+    TestFilterOperator testFilterOperator = new TestFilterOperator(docIds, 
numDocs);
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getTrues()), 
Collections.emptyList());
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getFalses()),
+        ImmutableList.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+  }
+
+  @Test
+  public void testBaseWithAllNulls() {
+    int numDocs = 10;
+    int[] docIds = new int[]{};
+    int[] nullDocIds = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+    TestFilterOperator testFilterOperator = new TestFilterOperator(docIds, 
nullDocIds, numDocs);
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getTrues()), 
Collections.emptyList());
+    Assert.assertEquals(TestUtils.getDocIds(testFilterOperator.getFalses()), 
Collections.emptyList());
+  }
+}
diff --git 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/OrFilterOperatorTest.java
 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/OrFilterOperatorTest.java
index 6e634351e9..b1c4aac1f8 100644
--- 
a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/OrFilterOperatorTest.java
+++ 
b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/OrFilterOperatorTest.java
@@ -21,6 +21,7 @@ package org.apache.pinot.core.operator.filter;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.TreeSet;
@@ -125,6 +126,22 @@ public class OrFilterOperatorTest {
     Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getFalses()), 
ImmutableList.of(8, 9));
   }
 
+  @Test
+  public void testOrWithNullHandlingDisabled() {
+    int numDocs = 10;
+    int[] docIds1 = new int[]{1, 2, 3};
+    int[] docIds2 = new int[]{0, 1, 2};
+    int[] nullDocIds1 = new int[]{};
+    int[] nullDocIds2 = new int[]{};
+
+    OrFilterOperator orFilterOperator = new OrFilterOperator(
+        Arrays.asList(new TestFilterOperator(docIds1, nullDocIds1, numDocs),
+            new TestFilterOperator(docIds2, nullDocIds2, numDocs)), null, 
numDocs, false);
+
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getTrues()), 
ImmutableList.of(0, 1, 2, 3));
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getFalses()), 
ImmutableList.of(4, 5, 6, 7, 8, 9));
+  }
+
   @Test
   public void testOrWithNullOneFilterIsEmpty() {
     int numDocs = 10;
@@ -138,4 +155,30 @@ public class OrFilterOperatorTest {
     Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getTrues()), 
Arrays.asList(1, 2, 3));
     Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getFalses()), 
Arrays.asList(0, 7, 8, 9));
   }
+
+  @Test
+  public void testOrWithNullOneFilterMatchesAll() {
+    int numDocs = 10;
+    int[] docIds1 = new int[]{1, 2, 3};
+    int[] nullDocIds1 = new int[]{4, 5, 6};
+
+    OrFilterOperator orFilterOperator = new OrFilterOperator(
+        Arrays.asList(new TestFilterOperator(docIds1, nullDocIds1, numDocs), 
new MatchAllFilterOperator(numDocs)), null,
+        numDocs, true);
+
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getTrues()), 
Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getFalses()), 
Collections.emptyList());
+  }
+
+  @Test
+  public void testOrWithAllEmpty() {
+    int numDocs = 10;
+
+    OrFilterOperator orFilterOperator =
+        new OrFilterOperator(Arrays.asList(EmptyFilterOperator.getInstance(), 
EmptyFilterOperator.getInstance()), null,
+            numDocs, true);
+
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getTrues()), 
Collections.emptyList());
+    Assert.assertEquals(TestUtils.getDocIds(orFilterOperator.getFalses()), 
Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+  }
 }


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

Reply via email to