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
2 changes: 2 additions & 0 deletions lucene/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ Optimizations
with fewer than 8 int lanes (Graviton2 and Graviton4). The vector compare beats the scalar
fallback by +75% on Graviton4 and +35% on Graviton2 (AdvanceBenchmark). (Shitij Bhargava)

* GITHUB#16349: Optimize IndexedDISI by implementing binary search for sparseDocs in advance methods (Rajat Jain)

* GITHUB#15681, GITHUB#15833, GITHUB#16056: Replace pre-sized array or empty array with lambda expression to call Collection#toArray. (Zhou Hui)

* GITHUB#13782: Replace handwritten loops compare with Arrays.compareUnsigned in TermsEnum and TermsEnumFrame classes. (Zhou Hui)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.DataInput;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.IndexOutput;
Expand Down Expand Up @@ -417,6 +418,8 @@ public static RandomAccessInput createJumpTable(

// SPARSE variables
boolean exists;
int[] sparseDocs;
int blockBaseIndex;

// DENSE variables
long word;
Expand Down Expand Up @@ -493,7 +496,12 @@ private void readBlockHeader() throws IOException {
nextBlockIndex = index + numValues;
if (numValues <= MAX_ARRAY_LENGTH) {
method = Method.SPARSE;
blockEnd = slice.getFilePointer() + (numValues << 1);
sparseDocs = new int[numValues];
for (int i = 0; i < numValues; i++) {
sparseDocs[i] = Short.toUnsignedInt(slice.readShort());
}
blockEnd = slice.getFilePointer();
blockBaseIndex = index;
} else if (numValues == 65536) {
method = Method.ALL;
blockEnd = slice.getFilePointer();
Expand Down Expand Up @@ -542,39 +550,37 @@ enum Method {
@Override
boolean advanceWithinBlock(IndexedDISI disi, int target) throws IOException {
final int targetInBlock = target & 0xFFFF;
// TODO: binary search
for (; disi.index < disi.nextBlockIndex; ) {
int doc = Short.toUnsignedInt(disi.slice.readShort());
disi.index++;
if (doc >= targetInBlock) {
disi.doc = disi.block | doc;
disi.exists = true;
return true;
}
final int start = disi.index - disi.blockBaseIndex;
final int end = disi.nextBlockIndex - disi.blockBaseIndex;
int pos = Arrays.binarySearch(disi.sparseDocs, start, end, targetInBlock);
if (pos < 0) {
pos = -pos - 1;
}
return false;
if (pos >= end) {
return false;
}
int doc = disi.sparseDocs[pos];
disi.index = disi.blockBaseIndex + pos + 1;
disi.doc = disi.block | doc;
disi.exists = true;
return true;
}

@Override
boolean advanceExactWithinBlock(IndexedDISI disi, int target) throws IOException {
final int targetInBlock = target & 0xFFFF;
// TODO: binary search
if (target == disi.doc) {
return disi.exists;
}
for (; disi.index < disi.nextBlockIndex; ) {
int doc = Short.toUnsignedInt(disi.slice.readShort());
disi.index++;
if (doc >= targetInBlock) {
if (doc != targetInBlock) {
disi.index--;
disi.slice.seek(disi.slice.getFilePointer() - Short.BYTES);
break;
}
disi.exists = true;
return true;
}
final int start = disi.index - disi.blockBaseIndex;
final int end = disi.nextBlockIndex - disi.blockBaseIndex;
int pos = Arrays.binarySearch(disi.sparseDocs, start, end, targetInBlock);
if (pos >= 0) {
disi.index = disi.blockBaseIndex + pos + 1;
disi.exists = true;
return true;
}
disi.index = disi.blockBaseIndex + (-pos - 1);
disi.exists = false;
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.DataInput;
import java.io.IOException;
import java.util.Arrays;
import org.apache.lucene.index.KnnVectorValues;
import org.apache.lucene.search.AbstractDocIdSetIterator;
import org.apache.lucene.search.DocIdSetIterator;
Expand Down Expand Up @@ -408,6 +409,8 @@ public static RandomAccessInput createJumpTable(
// SPARSE variables
boolean exists;
int nextExistDocInBlock = -1;
int[] sparseDocs;
int blockBaseIndex;

// DENSE variables
long word;
Expand Down Expand Up @@ -524,7 +527,15 @@ private void readBlockHeader() throws IOException {
nextBlockIndex = index + numValues;
if (numValues <= MAX_ARRAY_LENGTH) {
method = Method.SPARSE;
blockEnd = slice.getFilePointer() + (numValues << 1);
// Pre-load sparse block into memory so we can binary-search within it instead of
// streaming reads. This avoids repeated slice reads for multiple advances inside
// the same block.
blockBaseIndex = index;
sparseDocs = new int[numValues];
for (int i = 0; i < numValues; i++) {
sparseDocs[i] = Short.toUnsignedInt(slice.readShort());
}
blockEnd = slice.getFilePointer();
nextExistDocInBlock = -1;
} else if (numValues == BLOCK_SIZE) {
method = Method.ALL;
Expand Down Expand Up @@ -579,57 +590,68 @@ enum Method {
@Override
boolean advanceWithinBlock(IndexedDISI disi, int target) throws IOException {
final int targetInBlock = target & 0xFFFF;
// TODO: binary search
for (; disi.index < disi.nextBlockIndex; ) {
int doc = Short.toUnsignedInt(disi.slice.readShort());
disi.index++;
if (doc >= targetInBlock) {
disi.doc = disi.block | doc;
disi.exists = true;
disi.nextExistDocInBlock = doc;
return true;
}
final int start = Math.max(0, disi.index - disi.blockBaseIndex);
final int end = disi.nextBlockIndex - disi.blockBaseIndex;
if (start >= end) {
return false;
}
return false;
int pos = Arrays.binarySearch(disi.sparseDocs, start, end, targetInBlock);
if (pos < 0) {
pos = -pos - 1;
}
if (pos >= end) {
return false;
}
disi.index = disi.blockBaseIndex + pos + 1; // advance index to one past found
int docInBlock = disi.sparseDocs[pos];
disi.doc = disi.block | docInBlock;
disi.exists = true;
disi.nextExistDocInBlock = docInBlock;
return true;
}

@Override
boolean advanceExactWithinBlock(IndexedDISI disi, int target) throws IOException {
final int targetInBlock = target & 0xFFFF;
// TODO: binary search
if (disi.nextExistDocInBlock > targetInBlock) {
assert !disi.exists;
return false;
}
if (target == disi.doc) {
return disi.exists;
}
for (; disi.index < disi.nextBlockIndex; ) {
int doc = Short.toUnsignedInt(disi.slice.readShort());
disi.index++;
if (doc >= targetInBlock) {
disi.nextExistDocInBlock = doc;
if (doc != targetInBlock) {
disi.index--;
disi.slice.seek(disi.slice.getFilePointer() - Short.BYTES);
break;
}
disi.exists = true;
return true;
}
final int start = Math.max(0, disi.index - disi.blockBaseIndex);
final int end = disi.nextBlockIndex - disi.blockBaseIndex;
if (start >= end) {
disi.exists = false;
return false;
}
disi.exists = false;
return false;
int pos = Arrays.binarySearch(disi.sparseDocs, start, end, targetInBlock);
if (pos < 0) {
pos = -pos - 1;
}
if (pos >= end || disi.sparseDocs[pos] != targetInBlock) {
disi.exists = false;
// set index to position where next greater element would be
disi.index = disi.blockBaseIndex + pos;
return false;
}
// found exact match
disi.exists = true;
disi.index = disi.blockBaseIndex + pos + 1; // one past found
return true;
}

@Override
boolean intoBitSetWithinBlock(IndexedDISI disi, int upTo, FixedBitSet bitSet, int offset)
throws IOException {
bitSet.set(disi.doc - offset);
for (; disi.index < disi.nextBlockIndex; ) {
int docInBlock = disi.slice.readShort() & 0xFFFF;
final int start = Math.max(0, disi.index - disi.blockBaseIndex);
final int end = disi.nextBlockIndex - disi.blockBaseIndex;
for (int i = start; i < end; i++) {
int docInBlock = disi.sparseDocs[i];
int doc = disi.block | docInBlock;
disi.index++;
disi.index = disi.blockBaseIndex + i + 1;
if (doc >= upTo) {
disi.doc = doc;
disi.exists = true;
Expand Down
Loading