From 68d16c2a65b4acd0ce1ca543ae53a82e2516f1e5 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Thu, 7 Dec 2017 14:08:46 +0100 Subject: [PATCH] LUCENE-8082: Fix NPE in TopFieldCollectors that don't track total hit count --- .../lucene/search/TopFieldCollector.java | 12 ++++++--- .../lucene/search/TestTopFieldCollector.java | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java index c3597e9da1c..3d85277fcb0 100644 --- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java +++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java @@ -121,9 +121,11 @@ public abstract class TopFieldCollector extends TopDocsCollector { final LeafFieldComparator[] comparators = queue.getComparators(context); final int[] reverseMul = queue.getReverseMul(); + final Sort indexSort = context.reader().getMetaData().getSort(); final boolean canEarlyTerminate = trackTotalHits == false && trackMaxScore == false && - canEarlyTerminate(sort, context.reader().getMetaData().getSort()); + indexSort != null && + canEarlyTerminate(sort, indexSort); final int initialTotalHits = totalHits; return new MultiComparatorLeafCollector(comparators, reverseMul, mayNeedScoresTwice) { @@ -212,7 +214,9 @@ public abstract class TopFieldCollector extends TopDocsCollector { this.trackTotalHits = trackTotalHits; // Must set maxScore to NEG_INF, or otherwise Math.max always returns NaN. - maxScore = Float.NEGATIVE_INFINITY; + if (trackMaxScore) { + maxScore = Float.NEGATIVE_INFINITY; + } FieldComparator[] comparators = queue.comparators; // Tell all comparators their top value: @@ -227,9 +231,11 @@ public abstract class TopFieldCollector extends TopDocsCollector { public LeafCollector getLeafCollector(LeafReaderContext context) throws IOException { docBase = context.docBase; final int afterDoc = after.doc - docBase; + final Sort indexSort = context.reader().getMetaData().getSort(); final boolean canEarlyTerminate = trackTotalHits == false && trackMaxScore == false && - canEarlyTerminate(sort, context.reader().getMetaData().getSort()); + indexSort != null && + canEarlyTerminate(sort, indexSort); final int initialTotalHits = totalHits; return new MultiComparatorLeafCollector(queue.getComparators(context), queue.getReverseMul(), mayNeedScoresTwice) { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java index 0b7dc5b501c..d8363f7cfd8 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java @@ -102,6 +102,31 @@ public class TestTopFieldCollector extends LuceneTestCase { assertTrue(Float.isNaN(td.getMaxScore())); } } + + public void testSortWithoutTotalHitTracking() throws Exception { + Sort sort = new Sort(SortField.FIELD_DOC); + for(int i = 0; i < 2; i++) { + Query q = new MatchAllDocsQuery(); + // check that setting trackTotalHits to false does not throw an NPE because + // the index is not sorted + TopDocsCollector tdc; + if (i % 2 == 0) { + tdc = TopFieldCollector.create(sort, 10, true, false, false, false); + } else { + FieldDoc fieldDoc = new FieldDoc(1, Float.NaN, new Object[] { 1 }); + tdc = TopFieldCollector.create(sort, 10, fieldDoc, true, false, false, false); + } + + is.search(q, tdc); + + TopDocs td = tdc.topDocs(); + ScoreDoc[] sd = td.scoreDocs; + for(int j = 0; j < sd.length; j++) { + assertTrue(Float.isNaN(sd[j].score)); + } + assertTrue(Float.isNaN(td.getMaxScore())); + } + } public void testSortWithScoreNoMaxScoreTracking() throws Exception {