Skip to content

Commit 5e7fcf1

Browse files
authored
Merge branch 'main' into lucene/case-folding-table
2 parents 76e42d1 + fdd5963 commit 5e7fcf1

10 files changed

Lines changed: 1266 additions & 18 deletions

lucene/CHANGES.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ New Features
126126

127127
* GITHUB#15818: Add BM25 k3 query-term frequency saturation to BM25Similarity. (Sagar Upadhyaya)
128128

129+
* GITHUB#16383: Add fp16 vector encoding support. (Pulkit Gupta)
130+
129131
Improvements
130132
---------------------
131133
* GITHUB#15704: Replace LinkedList with more efficient data structure. (Renato Haeberli)
@@ -360,6 +362,8 @@ Optimizations
360362

361363
* GITHUG#16280: Single-pass writeString fast path for short strings in ByteBuffersDataOutput (neoremind)
362364

365+
* GITHUB#16220: Implement WANDScorer.advanceShallow() to enable block-max optimizations when nested in conjunctions. (Prithvi S)
366+
363367
* GITHUB#16146: Speed up no-score filtered-optional Boolean queries by routing dense conjunctions with cached FixedBitSet filters
364368
through ConstantScoreBulkScorer, which batches matches in bulk via DocIdStream. (Costin Leau)
365369

@@ -392,6 +396,8 @@ Optimizations
392396
* GITHUB#16380: Speed up filtered disjunction queries when the filter is part of the
393397
index sort by advancing the filter before calculating impacts. (Alan Woodward)
394398

399+
* GITHUB#16180: Add bulk intoBitSet for SortedDocValues ordinal ranges. (Prithvi S)
400+
395401
Bug Fixes
396402
---------------------
397403
* GITHUB#16350: Disable bulk-scoring in monitor queries. (Alan Woodward)

lucene/core/src/java/org/apache/lucene/codecs/lucene90/Lucene90DocValuesProducer.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,15 @@ public void intoBitSet(int upTo, FixedBitSet bitSet, int offset) throws IOExcept
14851485
advance(upTo);
14861486
}
14871487
}
1488+
1489+
@Override
1490+
public void ordinalRangeIntoBitSet(
1491+
int fromDoc, int toDoc, long minOrd, long maxOrd, FixedBitSet bitSet, int offset)
1492+
throws IOException {
1493+
// Dense packed ordinals: bulk evaluate via the same SIMD path as NumericDocValues
1494+
Lucene90DocValuesProducer.rangeIntoBitSet(
1495+
values, fromDoc, toDoc, minOrd, maxOrd, bitSet, offset);
1496+
}
14881497
};
14891498
} else if (ordsEntry.docsWithFieldOffset >= 0) { // sparse but non-empty
14901499
final IndexedDISI disi =
@@ -1583,6 +1592,15 @@ public int docIDRunEnd() throws IOException {
15831592
public void intoBitSet(int upTo, FixedBitSet bitSet, int offset) throws IOException {
15841593
ords.intoBitSet(upTo, bitSet, offset);
15851594
}
1595+
1596+
@Override
1597+
public void ordinalRangeIntoBitSet(
1598+
int fromDoc, int toDoc, long minOrd, long maxOrd, FixedBitSet bitSet, int offset)
1599+
throws IOException {
1600+
// Delegate to the underlying NumericDocValues which already has a (possibly SIMD)
1601+
// rangeIntoBitSet override.
1602+
ords.rangeIntoBitSet(fromDoc, toDoc, minOrd, maxOrd, bitSet, offset);
1603+
}
15861604
};
15871605
}
15881606

lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import org.apache.lucene.util.BytesRef;
21+
import org.apache.lucene.util.FixedBitSet;
2122
import org.apache.lucene.util.automaton.CompiledAutomaton;
2223

2324
/**
@@ -95,6 +96,32 @@ public TermsEnum termsEnum() throws IOException {
9596
return new SortedDocValuesTermsEnum(this);
9697
}
9798

99+
/**
100+
* Fills {@code bitSet} with the doc IDs in {@code [fromDoc, toDoc)} whose ordinals are in {@code
101+
* [minOrd, maxOrd]}. This is a bulk operation that avoids per-doc virtual dispatch overhead.
102+
*
103+
* <p>The default implementation falls back to per-doc evaluation via {@link #advanceExact} and
104+
* {@link #ordValue}. Subclasses with random-access storage (e.g., dense fixed-bitsPerValue
105+
* fields) can override this for significantly better performance.
106+
*
107+
* @param fromDoc first doc ID to evaluate (inclusive)
108+
* @param toDoc last doc ID to evaluate (exclusive)
109+
* @param minOrd lower bound of the ordinal range (inclusive)
110+
* @param maxOrd upper bound of the ordinal range (inclusive)
111+
* @param bitSet the bitset to fill
112+
* @param offset subtracted from each doc ID before setting the bit
113+
*/
114+
public void ordinalRangeIntoBitSet(
115+
int fromDoc, int toDoc, long minOrd, long maxOrd, FixedBitSet bitSet, int offset)
116+
throws IOException {
117+
for (int doc = docID() >= fromDoc ? docID() : advance(fromDoc); doc < toDoc; doc = nextDoc()) {
118+
long ord = ordValue();
119+
if (ord >= minOrd && ord <= maxOrd) {
120+
bitSet.set(doc - offset);
121+
}
122+
}
123+
}
124+
98125
/**
99126
* Returns a {@link TermsEnum} over the values, filtered by a {@link CompiledAutomaton} The enum
100127
* supports {@link TermsEnum#ord()}.

lucene/core/src/java/org/apache/lucene/search/DocValuesRangeIterator.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lucene/core/src/java/org/apache/lucene/search/WANDScorer.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -566,17 +566,18 @@ public float score() throws IOException {
566566

567567
@Override
568568
public int advanceShallow(int target) throws IOException {
569-
// Propagate to improve score bounds
569+
// Propagate to sub-scorers. Scorers past target constrain the boundary to docID - 1.
570+
int newUpTo = DocIdSetIterator.NO_MORE_DOCS;
570571
for (Scorer scorer : allScorers) {
571-
if (scorer.docID() < target) {
572-
scorer.advanceShallow(target);
572+
// Use <= instead of < so we still propagate and use the block boundary when already at
573+
// target.
574+
if (scorer.docID() <= target) {
575+
newUpTo = Math.min(newUpTo, scorer.advanceShallow(target));
576+
} else if (scorer.docID() != DocIdSetIterator.NO_MORE_DOCS) {
577+
newUpTo = Math.min(newUpTo, scorer.docID() - 1);
573578
}
574579
}
575-
if (target <= upTo) {
576-
return upTo;
577-
}
578-
// TODO: implement
579-
return DocIdSetIterator.NO_MORE_DOCS;
580+
return newUpTo;
580581
}
581582

582583
@Override

lucene/core/src/test/org/apache/lucene/search/TestConstantScoreScorer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public void testNextDocsAndScoresRandomClusteredDeletions() throws IOException {
318318
// scattered deletions.
319319
FixedBitSet liveDocs = new FixedBitSet(maxDoc);
320320
liveDocs.set(0, maxDoc);
321-
int runLength = TestUtil.nextInt(random(), 2 * 4096, 3 * 4096);
321+
int runLength = TestUtil.nextInt(random(), 2 * 4096, Math.min(3 * 4096, maxDoc));
322322
int runStart = TestUtil.nextInt(random(), 0, maxDoc - runLength);
323323
liveDocs.clear(runStart, runStart + runLength);
324324
for (int i = 0, scattered = random().nextInt(100); i < scattered; ++i) {

lucene/core/src/test/org/apache/lucene/search/TestDocValuesOrdinalRangeIterator.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,12 @@ public int getValueCount() {
134134

135135
@Override
136136
public boolean advanceExact(int target) {
137-
throw new UnsupportedOperationException();
137+
if (docHasValue(target)) {
138+
doc = target;
139+
return true;
140+
}
141+
doc = target;
142+
return false;
138143
}
139144

140145
@Override
@@ -349,7 +354,12 @@ public long getValueCount() {
349354

350355
@Override
351356
public boolean advanceExact(int target) {
352-
throw new UnsupportedOperationException();
357+
if (docHasValue(target)) {
358+
doc = target;
359+
return true;
360+
}
361+
doc = target;
362+
return false;
353363
}
354364

355365
@Override

lucene/core/src/test/org/apache/lucene/search/TestDocValuesOrdinalSetIterator.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,12 @@ public int getValueCount() {
209209

210210
@Override
211211
public boolean advanceExact(int target) {
212-
throw new UnsupportedOperationException();
212+
if (docHasValue(target)) {
213+
doc = target;
214+
return true;
215+
}
216+
doc = target;
217+
return false;
213218
}
214219

215220
@Override
@@ -500,7 +505,12 @@ public long getValueCount() {
500505

501506
@Override
502507
public boolean advanceExact(int target) {
503-
throw new UnsupportedOperationException();
508+
if (docHasValue(target)) {
509+
doc = target;
510+
return true;
511+
}
512+
doc = target;
513+
return false;
504514
}
505515

506516
@Override

0 commit comments

Comments
 (0)