@@ -99,8 +99,8 @@ public static DocValuesRangeIterator forOrdinalRange(
9999 };
100100 return skipper == null
101101 ? new DocValuesValueRangeIterator (values , check , 2 )
102- : new BulkOrdinalRangeIterator (
103- values , new SkipBlockRangeIterator (skipper , min , max ), check , 2 );
102+ : new BulkSortedRangeIterator (
103+ values , new SkipBlockRangeIterator (skipper , min , max ), check , 2 , min , max );
104104 }
105105
106106 /**
@@ -474,9 +474,43 @@ void intoMaybeBlock(int blockStart, int blockEnd, FixedBitSet bitSet, int offset
474474 }
475475
476476 /**
477- * Bulk range iterator over ordinal (sorted / sorted-set) doc values. There is no columnar
478- * range-decode like the numeric path, so MAYBE blocks confirm the ordinal predicate one doc at a
479- * time, visiting only docs that have a value.
477+ * Bulk range iterator over single-valued sorted (ordinal) doc values. Delegates MAYBE blocks to
478+ * {@link SortedDocValues#ordinalRangeIntoBitSet} so that dense packed implementations can use
479+ * direct (SIMD) range evaluation over the ordinal array.
480+ */
481+ private static final class BulkSortedRangeIterator extends BulkBlockRangeIterator {
482+
483+ private final SortedDocValues sortedValues ;
484+ private final long minOrd ;
485+ private final long maxOrd ;
486+
487+ private BulkSortedRangeIterator (
488+ SortedDocValues values ,
489+ SkipBlockRangeIterator blockIterator ,
490+ IOBooleanSupplier predicate ,
491+ float matchCost ,
492+ long minOrd ,
493+ long maxOrd ) {
494+ super (values , blockIterator , predicate , matchCost );
495+ this .sortedValues = values ;
496+ this .minOrd = minOrd ;
497+ this .maxOrd = maxOrd ;
498+ }
499+
500+ @ Override
501+ void intoMaybeBlock (int blockStart , int blockEnd , FixedBitSet bitSet , int offset )
502+ throws IOException {
503+ // sortedValues is the same instance as disi, so a preceding matches() call may have
504+ // moved it beyond blockStart. Adjust the starting point.
505+ int from = Math .max (blockStart , sortedValues .docID ());
506+ sortedValues .ordinalRangeIntoBitSet (from , blockEnd , minOrd , maxOrd , bitSet , offset );
507+ }
508+ }
509+
510+ /**
511+ * Bulk range iterator over ordinal (sorted-set) doc values. There is no columnar range-decode
512+ * like the numeric path, and for multi-valued we must check the predicate (which walks the
513+ * per-doc ords), so MAYBE blocks confirm by visiting only docs that have a value.
480514 */
481515 private static final class BulkOrdinalRangeIterator extends BulkBlockRangeIterator {
482516
0 commit comments