xiangfu0 commented on code in PR #20042:
URL: https://github.com/apache/pinot/pull/20042#discussion_r4376994663


##########
pinot-core/src/main/java/org/apache/pinot/core/operator/filter/InvertedIndexFilterOperator.java:
##########
@@ -169,11 +168,29 @@ public BitmapCollection getBitmaps() {
     int[] dictIds = _exclusive ? _predicateEvaluator.getNonMatchingDictIds() : 
_predicateEvaluator.getMatchingDictIds();
     ImmutableRoaringBitmap[] bitmaps = new 
ImmutableRoaringBitmap[dictIds.length];
     for (int i = 0; i < dictIds.length; i++) {
-      bitmaps[i] = _invertedIndexReader.getDocIds(dictIds[i]);
+      bitmaps[i] = getDocIds(dictIds[i]);
     }
     return new BitmapCollection(_numDocs, _exclusive, 
bitmaps).excludingNulls(getNullBitmap());
   }
 
+  /// Returns the documents for the given dictionary id, limited to `[0, 
numDocs)`.
+  ///
+  /// On a consuming segment, rows keep being indexed after the query is 
planned, so the bitmap read at execution time
+  /// can hold documents at or above `numDocs`, which is read at planning 
time. These documents must be dropped: the
+  /// flip for exclusive predicates only covers `[0, numDocs)`, so they would 
stay in the result, and the AND and count
+  /// paths don't check the document range again.

Review Comment:
   Nice fix, and good call on the trim-based approach over bounding the 
iterators. One consistency note: the sibling PR #20043 adds 
`FilterOperatorUtils.limitToNumDocs(bitmap, numDocs)` with essentially this 
same logic. Worth reconciling the two so there's a single implementation — or, 
if you keep this private copy deliberately (it reuses the 
`MutableRoaringBitmap` in place and avoids the extra `toMutableRoaringBitmap()` 
clone that `limitToNumDocs` always does), a one-line comment pointing to 
`limitToNumDocs` and explaining why this one diverges would save the next 
reader the diff.



##########
pinot-core/src/main/java/org/apache/pinot/core/operator/filter/InvertedIndexFilterOperator.java:
##########
@@ -169,11 +168,29 @@ public BitmapCollection getBitmaps() {
     int[] dictIds = _exclusive ? _predicateEvaluator.getNonMatchingDictIds() : 
_predicateEvaluator.getMatchingDictIds();
     ImmutableRoaringBitmap[] bitmaps = new 
ImmutableRoaringBitmap[dictIds.length];
     for (int i = 0; i < dictIds.length; i++) {
-      bitmaps[i] = _invertedIndexReader.getDocIds(dictIds[i]);
+      bitmaps[i] = getDocIds(dictIds[i]);
     }
     return new BitmapCollection(_numDocs, _exclusive, 
bitmaps).excludingNulls(getNullBitmap());
   }
 
+  /// Returns the documents for the given dictionary id, limited to `[0, 
numDocs)`.
+  ///
+  /// On a consuming segment, rows keep being indexed after the query is 
planned, so the bitmap read at execution time
+  /// can hold documents at or above `numDocs`, which is read at planning 
time. These documents must be dropped: the
+  /// flip for exclusive predicates only covers `[0, numDocs)`, so they would 
stay in the result, and the AND and count
+  /// paths don't check the document range again.
+  private ImmutableRoaringBitmap getDocIds(int dictId) {
+    ImmutableRoaringBitmap docIds = _invertedIndexReader.getDocIds(dictId);
+    if (docIds.isEmpty() || docIds.last() < _numDocs) {
+      return docIds;
+    }
+    // Only a mutable inverted index can hold such documents, and it returns a 
copy of its bitmap
+    MutableRoaringBitmap mutableDocIds =
+        docIds instanceof MutableRoaringBitmap ? (MutableRoaringBitmap) docIds 
: docIds.toMutableRoaringBitmap();
+    mutableDocIds.remove(_numDocs, 0x100000000L);

Review Comment:
   The in-place `remove` on the `MutableRoaringBitmap` branch (no copy) is safe 
only because the mutable inverted index hands back a `.clone()` on every 
`getDocIds` call — verified in 
`RealtimeInvertedIndex`/`ThreadSafeMutableRoaringBitmap`. That's a load-bearing 
assumption; a short comment here noting "the mutable index already returns a 
fresh clone, so we can trim in place" would protect it against future index 
changes.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to