Skip to content

Commit 8e8e37d

Browse files
authored
Fix potential NPE for KnnVectorQuery (#15334)
* Fix potential NPE for KnnVectorQuery * adding test * removing unused test code
1 parent e3184cb commit 8e8e37d

File tree

3 files changed

+26
-3
lines changed

3 files changed

+26
-3
lines changed

lucene/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ Bug Fixes
214214

215215
* GITHUB#15319: Fix potential hang in initialisation of TermsEnum and BaseTermsEnum (Chris Hegarty)
216216

217+
* GITHUB#15334: Fix NPE for MemoryIndex when using nearest neighbor search. MemoryIndex does not support
218+
nearest neighbor search, but it should not throw an NPE (Ben Trent)
219+
217220
Other
218221
---------------------
219222
* GITHUB#15237: Fix SmartChinese to only deserialize dictionary data from classpath with a native array

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,15 @@ private TopDocs getLeafResults(
211211
final int cost = acceptDocs.cost();
212212
QueryTimeout queryTimeout = timeLimitingKnnCollectorManager.getQueryTimeout();
213213

214-
float leafProportion = ctx.reader().maxDoc() / (float) ctx.parent.reader().maxDoc();
215-
int perLeafTopK = perLeafTopKCalculation(k, leafProportion);
214+
final int perLeafTopK;
215+
// ctx.parent could be null if this is a MemoryIndex
216+
if (ctx.parent != null) {
217+
float leafProportion = ctx.reader().maxDoc() / (float) ctx.parent.reader().maxDoc();
218+
perLeafTopK = perLeafTopKCalculation(k, leafProportion);
219+
// We don't have a good way to estimate perLeafTopK here, so just do approximate search
220+
} else {
221+
perLeafTopK = k;
222+
}
216223

217224
if (cost <= perLeafTopK) {
218225
// If there are <= perLeafTopK possible matches, short-circuit and perform exact search, since
@@ -255,7 +262,8 @@ public KnnCollector newCollector(
255262
int visitedLimit, KnnSearchStrategy searchStrategy, LeafReaderContext context)
256263
throws IOException {
257264
// The delegate supports optimistic collection
258-
if (delegate.isOptimistic()) {
265+
// ctx.parent could be null if this is a MemoryIndex
266+
if (delegate.isOptimistic() && context.parent != null) {
259267
@SuppressWarnings("resource")
260268
float leafProportion = context.reader().maxDoc() / (float) context.parent.reader().maxDoc();
261269
int perLeafTopK = perLeafTopKCalculation(k, leafProportion);

lucene/memory/src/test/org/apache/lucene/index/memory/TestMemoryIndex.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,14 @@
7777
import org.apache.lucene.search.CollectionStatistics;
7878
import org.apache.lucene.search.DocIdSetIterator;
7979
import org.apache.lucene.search.IndexSearcher;
80+
import org.apache.lucene.search.KnnByteVectorQuery;
81+
import org.apache.lucene.search.KnnFloatVectorQuery;
8082
import org.apache.lucene.search.MatchAllDocsQuery;
8183
import org.apache.lucene.search.PhraseQuery;
8284
import org.apache.lucene.search.Query;
8385
import org.apache.lucene.search.TermQuery;
8486
import org.apache.lucene.search.TermStatistics;
87+
import org.apache.lucene.search.TopDocs;
8588
import org.apache.lucene.search.VectorScorer;
8689
import org.apache.lucene.search.similarities.BM25Similarity;
8790
import org.apache.lucene.search.similarities.ClassicSimilarity;
@@ -793,6 +796,11 @@ public void testKnnFloatVectors() throws IOException {
793796
.get(0)
794797
.reader()
795798
.getByteVectorValues("knnByteVectorValue"));
799+
TopDocs docs =
800+
mi.createSearcher()
801+
.search(new KnnFloatVectorQuery("knnFloatA", new float[] {1.0f, 1.0f}, 1), 10);
802+
// we don't really do knn search right now for MemoryIndex
803+
assertEquals(0, docs.totalHits.value());
796804
}
797805

798806
public void testKnnByteVectorOnlyOneVectorAllowed() throws IOException {
@@ -840,6 +848,10 @@ public void testKnnByteVectors() throws IOException {
840848
.get(0)
841849
.reader()
842850
.getFloatVectorValues("knnFloatVectorValue"));
851+
TopDocs docs =
852+
mi.createSearcher().search(new KnnByteVectorQuery("knnByteA", new byte[] {1, 1}, 1), 10);
853+
// we don't really do knn search right now for MemoryIndex
854+
assertEquals(0, docs.totalHits.value());
843855
}
844856

845857
private static void assertFloatVectorValue(MemoryIndex mi, String fieldName, float[] expected)

0 commit comments

Comments
 (0)