diff --git a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BitmapCollection.java b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BitmapCollection.java index b3f40ed41f6b..04fddee856e3 100644 --- a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BitmapCollection.java +++ b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/BitmapCollection.java @@ -86,11 +86,10 @@ public int orCardinality(BitmapCollection bitmaps) { if (!bitmaps._inverted) { return ImmutableRoaringBitmap.orCardinality(left, right); } - return _numDocs - right.getCardinality() - ImmutableRoaringBitmap.andCardinality(left, right); + return _numDocs - right.getCardinality() + ImmutableRoaringBitmap.andCardinality(left, right); } else { if (!bitmaps._inverted) { - return _numDocs - left.getCardinality() - + ImmutableRoaringBitmap.andCardinality(right, left); + return _numDocs - left.getCardinality() + ImmutableRoaringBitmap.andCardinality(right, left); } return _numDocs - ImmutableRoaringBitmap.andCardinality(left, right); } diff --git a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BitmapCollectionTest.java b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BitmapCollectionTest.java index e7985a0369e1..5224b35f9d79 100644 --- a/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BitmapCollectionTest.java +++ b/pinot-core/src/test/java/org/apache/pinot/core/operator/filter/BitmapCollectionTest.java @@ -171,7 +171,7 @@ public static Object[][] orCardinalityTestCases() { }, { 10, ImmutableRoaringBitmap.bitmapOf(0, 5), false, - ImmutableRoaringBitmap.bitmapOf(0, 4), true, 7 + ImmutableRoaringBitmap.bitmapOf(0, 4), true, 9 }, { 10, ImmutableRoaringBitmap.bitmapOf(0, 5), false, diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java index f323a88b7a25..9e287cb28473 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/OfflineClusterIntegrationTest.java @@ -3762,4 +3762,19 @@ public void testFilteredAggregationWithNoValueMatchingAggregationFilterWithOptio // empty groups assertEquals(result.get("numRowsResultSet").asInt(), 0); } + + @Test(dataProvider = "useBothQueryEngines") + public void testFastFilteredCountWithOrFilterOnBitmapWithExclusiveBitmap(boolean useMultiStageQueryEngine) + throws Exception { + setUseMultiStageQueryEngine(useMultiStageQueryEngine); + // Column "Origin" has a range index, and column "DayofMonth" has a sorted index in several segments. This means + // that the count aggregation will be executed using the fast filtered count operator in these segments. The range + // index will produce a non-inverted bitmap collection and the sorted index will produce an inverted bitmap + // collection (since the filter predicate is exclusive). + + // See this issue - https://github.com/apache/pinot/issues/14486 + testQuery( + "SELECT COUNT(*) FROM mytable WHERE Origin BETWEEN 'ALB' AND 'LMT' OR DayofMonth <> 2" + ); + } }