Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@ Improvements

Optimizations
---------------------
(No changes)
* GITHUB#16283: Use Panama Vector API to SIMD-evaluate fixed-cardinality sorted numeric range
queries in rangeIntoBitSet. (Costin Leau)

Bug Fixes
---------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,29 +495,6 @@ private static int fixedCardinality(
return (int) cardinality;
}

private static void sortedNumericScalarRangeIntoBitSet(
LongValues values,
int fromDoc,
int toDoc,
int cardinality,
long minValue,
long maxValue,
FixedBitSet bitSet,
int offset) {
for (int doc = fromDoc; doc < toDoc; doc++) {
long valueOffset = (long) doc * cardinality;
for (int i = 0; i < cardinality; i++) {
long value = values.get(valueOffset + i);
if (value >= minValue) {
if (value <= maxValue) {
bitSet.set(doc - offset);
}
break;
}
}
}
}

private static boolean sortedNumericMatchesRange(
LongValues values, long start, long end, long minValue, long maxValue) {
for (long valueOffset = start; valueOffset < end; valueOffset++) {
Expand Down Expand Up @@ -1906,7 +1883,7 @@ public void rangeIntoBitSet(
}
int cardinality = denseFixedCardinality;
if (cardinality > 1) {
sortedNumericScalarRangeIntoBitSet(
DOC_VALUES_RANGE_SUPPORT.sortedNumericRangeIntoBitSet(
values, fromDoc, endDoc, cardinality, minValue, maxValue, bitSet, offset);
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,36 @@ void rangeIntoBitSet(
long maxValue,
FixedBitSet bitSet,
int offset);

/**
* Fills {@code bitSet} with docs in {@code [fromDoc, toDoc)} whose sorted numeric values contain
* at least one value in {@code [minValue, maxValue]}.
*
* <p>This method only supports <b>fixed-cardinality</b> fields where every document has exactly
* {@code cardinality} values stored contiguously starting at index {@code doc * cardinality}.
*
* @param cardinality number of values per document (must be &gt; 0)
*/
default void sortedNumericRangeIntoBitSet(
LongValues values,
int fromDoc,
int toDoc,
int cardinality,
long minValue,
long maxValue,
FixedBitSet bitSet,
int offset) {
for (int doc = fromDoc; doc < toDoc; doc++) {
long valueOffset = (long) doc * cardinality;
for (int i = 0; i < cardinality; i++) {
long value = values.get(valueOffset + i);
if (value >= minValue) {
if (value <= maxValue) {
bitSet.set(doc - offset);
}
break;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,61 @@ public void rangeIntoBitSet(
}
}
}

@Override
public void sortedNumericRangeIntoBitSet(
LongValues values,
int fromDoc,
int toDoc,
int cardinality,
long minValue,
long maxValue,
FixedBitSet bitSet,
int offset) {
assert cardinality > 0 : "cardinality must be positive: " + cardinality;
final int vectorLen = LONG_SPECIES.length();
final int docsPerVector = vectorLen / cardinality;
Comment thread
costin marked this conversation as resolved.
if (docsPerVector == 0 || vectorLen % cardinality != 0) {
DocValuesRangeSupport.super.sortedNumericRangeIntoBitSet(
values, fromDoc, toDoc, cardinality, minValue, maxValue, bitSet, offset);
return;
}

final long[] scratch = new long[vectorLen];
final int vectorDocEnd = fromDoc + (toDoc - fromDoc) / docsPerVector * docsPerVector;
int doc = fromDoc;
for (; doc < vectorDocEnd; doc += docsPerVector) {
long valueOffset = (long) doc * cardinality;
for (int lane = 0; lane < vectorLen; lane++) {
scratch[lane] = values.get(valueOffset + lane);
}
Comment thread
costin marked this conversation as resolved.
LongVector vector = LongVector.fromArray(LONG_SPECIES, scratch, 0);
// Flat range check on all lanes. Equivalent to the scalar early-break on sorted values:
// a value outside [min,max] that is >= min must be > max, so its lane stays unset, and
// collapseToDocMask OR-reduces lanes per doc to match "any value in range" semantics.
VectorMask<Long> inRange =
vector
.compare(VectorOperators.GE, minValue)
.and(vector.compare(VectorOperators.LE, maxValue));
long docMask = collapseToDocMask(inRange.toLong(), cardinality, docsPerVector);
if (docMask != 0) {
bitSet.orMask(doc - offset, docMask, docsPerVector);
}
}

DocValuesRangeSupport.super.sortedNumericRangeIntoBitSet(
values, doc, toDoc, cardinality, minValue, maxValue, bitSet, offset);
}

private static long collapseToDocMask(long valueMask, int cardinality, int docsPerVector) {
final long valueMaskPerDoc = (1L << cardinality) - 1L;
long docMask = 0L;
for (int d = 0; d < docsPerVector; d++) {
long perDoc = (valueMask >>> (d * cardinality)) & valueMaskPerDoc;
if (perDoc != 0) {
docMask |= 1L << d;
}
}
return docMask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -652,14 +652,25 @@ public void testSortedNumericRangeIntoBitSetSparseVariableCardinality() throws E

private void doTestSortedNumericRangeIntoBitSet(boolean dense, boolean fixedCardinality)
throws Exception {
doTestSortedNumericRangeIntoBitSet(dense, fixedCardinality, 4);
}

public void testSortedNumericRangeIntoBitSetVaryingCardinality() throws Exception {
for (int cardinality : new int[] {2, 3, 4, 5, 7, 8}) {
doTestSortedNumericRangeIntoBitSet(true, true, cardinality);
}
}

private void doTestSortedNumericRangeIntoBitSet(
boolean dense, boolean fixedCardinality, int fixedCardinalityValue) throws Exception {
int numDocs = 4096 * 2;
try (Directory dir = newDirectory()) {
IndexWriterConfig iwc = new IndexWriterConfig().setCodec(new Lucene104Codec());
try (IndexWriter w = new IndexWriter(dir, iwc)) {
for (int docID = 0; docID < numDocs; docID++) {
Document doc = new Document();
if (dense || docID % 3 != 0) {
int valueCount = fixedCardinality ? 4 : 1 + (docID & 3);
int valueCount = fixedCardinality ? fixedCardinalityValue : 1 + (docID & 3);
long firstValue = (docID * 13L) % 100;
for (int i = 0; i < valueCount; i++) {
doc.add(SortedNumericDocValuesField.indexedField("sn", firstValue + i * 3L));
Expand Down
Loading