diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index c86ec77b26f1..12c31ba0f6a5 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -291,6 +291,8 @@ Optimizations * GITHUB#15779: Improve BytesRefHash.add performance by optimize rehash operation (tyronecai) +* GITHUB#15879: Optimize TopGroups.merge() maxScore computation for relevance sorting (Binlong Gao) + * GITHUB#15886: Cache frozen FieldType to skip redundant schema validation. (Tim Brooks) Bug Fixes diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java index 0a1c607ab78b..3b75ccdeaa25 100644 --- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java +++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java @@ -153,7 +153,8 @@ public static TopGroups merge( final GroupDocs[] mergedGroupDocs = new GroupDocs[numGroups]; final TopDocs[] shardTopDocs; - if (docSort.equals(Sort.RELEVANCE)) { + final boolean sortByRelevance = docSort.equals(Sort.RELEVANCE); + if (sortByRelevance) { shardTopDocs = new TopDocs[shardGroups.length]; } else { shardTopDocs = new TopFieldDocs[shardGroups.length]; @@ -187,7 +188,7 @@ public static TopGroups merge( } */ - if (docSort.equals(Sort.RELEVANCE)) { + if (sortByRelevance) { shardTopDocs[shardIDX] = new TopDocs(shardGroupDocs.totalHits(), shardGroupDocs.scoreDocs()); } else { @@ -200,15 +201,21 @@ public static TopGroups merge( shardTopDocs[shardIDX].scoreDocs[i].shardIndex = shardIDX; } - maxScore = nonNANmax(maxScore, shardGroupDocs.maxScore()); + if (!sortByRelevance) { + maxScore = nonNANmax(maxScore, shardGroupDocs.maxScore()); + } assert shardGroupDocs.totalHits().relation() == Relation.EQUAL_TO; totalHits += shardGroupDocs.totalHits().value(); scoreSum += shardGroupDocs.score(); } final TopDocs mergedTopDocs; - if (docSort.equals(Sort.RELEVANCE)) { + if (sortByRelevance) { mergedTopDocs = TopDocs.merge(docOffset + docTopN, shardTopDocs); + // When sorting by relevance, the highest-scoring doc is first, so we can + // derive maxScore directly instead of accumulating across shards. + maxScore = + mergedTopDocs.scoreDocs.length == 0 ? Float.NaN : mergedTopDocs.scoreDocs[0].score; } else { mergedTopDocs = TopDocs.merge(docSort, docOffset + docTopN, (TopFieldDocs[]) shardTopDocs); }