mirror of https://github.com/apache/lucene.git
Make MaxScoreAccumulator use primitive long instead Object return (#13866)
An object return inside hot code like this is needlessly wasteful. Escape analysis doesn't catch this one and we end up allocating many GB of throwaway objects during benchmark runs. We might as well use two utility methods and accumulate the raw value.
This commit is contained in:
parent
7757d43f4c
commit
5d5dddd103
|
@ -35,8 +35,8 @@ final class MaxScoreAccumulator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the max encoded DocAndScore in a way that is consistent with {@link
|
||||
* DocAndScore#compareTo}.
|
||||
* Return the max encoded docId and score found in the two longs, following the encoding in {@link
|
||||
* #accumulate}.
|
||||
*/
|
||||
private static long maxEncode(long v1, long v2) {
|
||||
float score1 = Float.intBitsToFloat((int) (v1 >> 32));
|
||||
|
@ -57,26 +57,15 @@ final class MaxScoreAccumulator {
|
|||
acc.accumulate(encode);
|
||||
}
|
||||
|
||||
DocAndScore get() {
|
||||
long value = acc.get();
|
||||
if (value == Long.MIN_VALUE) {
|
||||
return null;
|
||||
}
|
||||
float score = Float.intBitsToFloat((int) (value >> 32));
|
||||
int docId = (int) value;
|
||||
return new DocAndScore(docId, score);
|
||||
public static float toScore(long value) {
|
||||
return Float.intBitsToFloat((int) (value >> 32));
|
||||
}
|
||||
|
||||
record DocAndScore(int docId, float score) implements Comparable<DocAndScore> {
|
||||
public static int docId(long value) {
|
||||
return (int) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DocAndScore o) {
|
||||
int cmp = Float.compare(score, o.score);
|
||||
if (cmp == 0) {
|
||||
// tie-break on doc id, lower id has the priority
|
||||
return Integer.compare(o.docId, docId);
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
long getRaw() {
|
||||
return acc.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.Objects;
|
|||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.index.ReaderUtil;
|
||||
import org.apache.lucene.search.FieldValueHitQueue.Entry;
|
||||
import org.apache.lucene.search.MaxScoreAccumulator.DocAndScore;
|
||||
import org.apache.lucene.search.TotalHits.Relation;
|
||||
|
||||
/**
|
||||
|
@ -366,10 +365,12 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
|
|||
// we can start checking the global maximum score even
|
||||
// if the local queue is not full because the threshold
|
||||
// is reached.
|
||||
DocAndScore maxMinScore = minScoreAcc.get();
|
||||
if (maxMinScore != null && maxMinScore.score() > minCompetitiveScore) {
|
||||
scorer.setMinCompetitiveScore(maxMinScore.score());
|
||||
minCompetitiveScore = maxMinScore.score();
|
||||
long maxMinScore = minScoreAcc.getRaw();
|
||||
float score;
|
||||
if (maxMinScore != Long.MIN_VALUE
|
||||
&& (score = MaxScoreAccumulator.toScore(maxMinScore)) > minCompetitiveScore) {
|
||||
scorer.setMinCompetitiveScore(score);
|
||||
minCompetitiveScore = score;
|
||||
totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package org.apache.lucene.search;
|
|||
|
||||
import java.io.IOException;
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.search.MaxScoreAccumulator.DocAndScore;
|
||||
|
||||
/**
|
||||
* A {@link Collector} implementation that collects the top-scoring hits, returning them as a {@link
|
||||
|
@ -226,13 +225,13 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
|
|||
|
||||
protected void updateGlobalMinCompetitiveScore(Scorable scorer) throws IOException {
|
||||
assert minScoreAcc != null;
|
||||
DocAndScore maxMinScore = minScoreAcc.get();
|
||||
if (maxMinScore != null) {
|
||||
long maxMinScore = minScoreAcc.getRaw();
|
||||
if (maxMinScore != Long.MIN_VALUE) {
|
||||
// since we tie-break on doc id and collect in doc id order we can require
|
||||
// the next float if the global minimum score is set on a document id that is
|
||||
// smaller than the ids in the current leaf
|
||||
float score =
|
||||
docBase >= maxMinScore.docId() ? Math.nextUp(maxMinScore.score()) : maxMinScore.score();
|
||||
float score = MaxScoreAccumulator.toScore(maxMinScore);
|
||||
score = docBase >= MaxScoreAccumulator.docId(maxMinScore) ? Math.nextUp(score) : score;
|
||||
if (score > minCompetitiveScore) {
|
||||
assert hitsThresholdChecker.isThresholdReached();
|
||||
scorer.setMinCompetitiveScore(score);
|
||||
|
|
|
@ -23,44 +23,28 @@ public class TestMaxScoreAccumulator extends LuceneTestCase {
|
|||
public void testSimple() {
|
||||
MaxScoreAccumulator acc = new MaxScoreAccumulator();
|
||||
acc.accumulate(0, 0f);
|
||||
assertEquals(0f, acc.get().score(), 0);
|
||||
assertEquals(0, acc.get().docId(), 0);
|
||||
assertEquals(0f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(0, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(10, 0f);
|
||||
assertEquals(0f, acc.get().score(), 0);
|
||||
assertEquals(0, acc.get().docId(), 0);
|
||||
assertEquals(0f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(0, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(100, 1000f);
|
||||
assertEquals(1000f, acc.get().score(), 0);
|
||||
assertEquals(100, acc.get().docId(), 0);
|
||||
assertEquals(1000f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(100, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(1000, 5f);
|
||||
assertEquals(1000f, acc.get().score(), 0);
|
||||
assertEquals(100, acc.get().docId(), 0);
|
||||
assertEquals(1000f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(100, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(99, 1000f);
|
||||
assertEquals(1000f, acc.get().score(), 0);
|
||||
assertEquals(99, acc.get().docId(), 0);
|
||||
assertEquals(1000f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(99, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(1000, 1001f);
|
||||
assertEquals(1001f, acc.get().score(), 0);
|
||||
assertEquals(1000, acc.get().docId(), 0);
|
||||
assertEquals(1001f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(1000, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(10, 1001f);
|
||||
assertEquals(1001f, acc.get().score(), 0);
|
||||
assertEquals(10, acc.get().docId(), 0);
|
||||
assertEquals(1001f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(10, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
acc.accumulate(100, 1001f);
|
||||
assertEquals(1001f, acc.get().score(), 0);
|
||||
assertEquals(10, acc.get().docId(), 0);
|
||||
}
|
||||
|
||||
public void testRandom() {
|
||||
MaxScoreAccumulator acc = new MaxScoreAccumulator();
|
||||
int numDocs = atLeast(100);
|
||||
int maxDocs = atLeast(10000);
|
||||
MaxScoreAccumulator.DocAndScore max = new MaxScoreAccumulator.DocAndScore(-1, -1);
|
||||
for (int i = 0; i < numDocs; i++) {
|
||||
MaxScoreAccumulator.DocAndScore res =
|
||||
new MaxScoreAccumulator.DocAndScore(random().nextInt(maxDocs), random().nextFloat());
|
||||
acc.accumulate(res.docId(), res.score());
|
||||
if (res.compareTo(max) > 0) {
|
||||
max = res;
|
||||
}
|
||||
}
|
||||
assertEquals(max, acc.get());
|
||||
assertEquals(1001f, MaxScoreAccumulator.toScore(acc.getRaw()), 0);
|
||||
assertEquals(10, MaxScoreAccumulator.docId(acc.getRaw()), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,47 +519,47 @@ public class TestTopDocsCollector extends LuceneTestCase {
|
|||
|
||||
scorer.score = 3;
|
||||
leafCollector.collect(0);
|
||||
assertNull(minValueChecker.get());
|
||||
assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
|
||||
assertNull(scorer.minCompetitiveScore);
|
||||
|
||||
scorer2.score = 6;
|
||||
leafCollector2.collect(0);
|
||||
assertNull(minValueChecker.get());
|
||||
assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
|
||||
assertNull(scorer2.minCompetitiveScore);
|
||||
|
||||
scorer.score = 2;
|
||||
leafCollector.collect(1);
|
||||
assertEquals(2f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(2f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
|
||||
assertNull(scorer2.minCompetitiveScore);
|
||||
|
||||
scorer2.score = 9;
|
||||
leafCollector2.collect(1);
|
||||
assertEquals(6f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(6f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(6f), scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer2.score = 7;
|
||||
leafCollector2.collect(2);
|
||||
assertEquals(minValueChecker.get().score(), 7f, 0f);
|
||||
assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 7f, 0f);
|
||||
assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer2.score = 1;
|
||||
leafCollector2.collect(3);
|
||||
assertEquals(minValueChecker.get().score(), 7f, 0f);
|
||||
assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 7f, 0f);
|
||||
assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 10;
|
||||
leafCollector.collect(2);
|
||||
assertEquals(minValueChecker.get().score(), 7f, 0f);
|
||||
assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 7f, 0f);
|
||||
assertEquals(7f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 11;
|
||||
leafCollector.collect(3);
|
||||
assertEquals(minValueChecker.get().score(), 10, 0f);
|
||||
assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 10, 0f);
|
||||
assertEquals(Math.nextUp(10f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
|
@ -571,19 +571,19 @@ public class TestTopDocsCollector extends LuceneTestCase {
|
|||
|
||||
scorer3.score = 1f;
|
||||
leafCollector3.collect(0);
|
||||
assertEquals(10f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(10f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(Math.nextUp(10f), scorer3.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 11;
|
||||
leafCollector.collect(4);
|
||||
assertEquals(11f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(11f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(Math.nextUp(11f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(10f), scorer3.minCompetitiveScore, 0f);
|
||||
|
||||
scorer3.score = 2f;
|
||||
leafCollector3.collect(1);
|
||||
assertEquals(minValueChecker.get().score(), 11f, 0f);
|
||||
assertEquals(MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 11f, 0f);
|
||||
assertEquals(Math.nextUp(11f), scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
|
||||
assertEquals(Math.nextUp(11f), scorer3.minCompetitiveScore, 0f);
|
||||
|
|
|
@ -577,47 +577,47 @@ public class TestTopFieldCollector extends LuceneTestCase {
|
|||
|
||||
scorer.score = 3;
|
||||
leafCollector.collect(0);
|
||||
assertNull(minValueChecker.get());
|
||||
assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
|
||||
assertNull(scorer.minCompetitiveScore);
|
||||
|
||||
scorer2.score = 6;
|
||||
leafCollector2.collect(0);
|
||||
assertNull(minValueChecker.get());
|
||||
assertEquals(Long.MIN_VALUE, minValueChecker.getRaw());
|
||||
assertNull(scorer2.minCompetitiveScore);
|
||||
|
||||
scorer.score = 2;
|
||||
leafCollector.collect(1);
|
||||
assertEquals(2f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(2f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(2f, scorer.minCompetitiveScore, 0f);
|
||||
assertNull(scorer2.minCompetitiveScore);
|
||||
|
||||
scorer2.score = 9;
|
||||
leafCollector2.collect(1);
|
||||
assertEquals(6f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(6f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(2f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(6f, scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer2.score = 7;
|
||||
leafCollector2.collect(2);
|
||||
assertEquals(7f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(7f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(2f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer2.score = 1;
|
||||
leafCollector2.collect(3);
|
||||
assertEquals(7f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(7f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(2f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 10;
|
||||
leafCollector.collect(2);
|
||||
assertEquals(7f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(7f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(7f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 11;
|
||||
leafCollector.collect(3);
|
||||
assertEquals(10f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(10f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(10f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
|
||||
|
@ -629,19 +629,19 @@ public class TestTopFieldCollector extends LuceneTestCase {
|
|||
|
||||
scorer3.score = 1f;
|
||||
leafCollector3.collect(0);
|
||||
assertEquals(10f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(10f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(10f, scorer3.minCompetitiveScore, 0f);
|
||||
|
||||
scorer.score = 11;
|
||||
leafCollector.collect(4);
|
||||
assertEquals(11f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(11f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(11f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
assertEquals(10f, scorer3.minCompetitiveScore, 0f);
|
||||
|
||||
scorer3.score = 2f;
|
||||
leafCollector3.collect(1);
|
||||
assertEquals(11f, minValueChecker.get().score(), 0f);
|
||||
assertEquals(11f, MaxScoreAccumulator.toScore(minValueChecker.getRaw()), 0f);
|
||||
assertEquals(11f, scorer.minCompetitiveScore, 0f);
|
||||
assertEquals(7f, scorer2.minCompetitiveScore, 0f);
|
||||
assertEquals(11f, scorer3.minCompetitiveScore, 0f);
|
||||
|
|
Loading…
Reference in New Issue