2021-10-14 15:55:58 +02:00
|
|
|
package it.cavallium.dbengine;
|
|
|
|
|
|
|
|
import com.google.common.collect.Lists;
|
2022-04-06 02:41:32 +02:00
|
|
|
import io.netty5.buffer.api.Buffer;
|
2021-12-18 21:01:14 +01:00
|
|
|
import it.cavallium.dbengine.database.SafeCloseable;
|
2022-04-06 02:41:32 +02:00
|
|
|
import it.cavallium.dbengine.database.disk.LLTempHugePqEnv;
|
2021-10-14 15:55:58 +02:00
|
|
|
import it.cavallium.dbengine.lucene.LLScoreDoc;
|
2022-04-06 02:41:32 +02:00
|
|
|
import it.cavallium.dbengine.lucene.HugePqCodec;
|
|
|
|
import it.cavallium.dbengine.lucene.HugePqPriorityQueue;
|
2021-10-14 15:55:58 +02:00
|
|
|
import it.cavallium.dbengine.lucene.PriorityQueue;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
2022-06-15 13:09:45 +02:00
|
|
|
import java.util.Comparator;
|
2021-10-14 15:55:58 +02:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Random;
|
2022-06-15 13:09:45 +02:00
|
|
|
import java.util.concurrent.ThreadLocalRandom;
|
2021-10-14 15:55:58 +02:00
|
|
|
import java.util.function.Function;
|
|
|
|
import org.apache.lucene.search.HitQueue;
|
|
|
|
import org.apache.lucene.search.ScoreDoc;
|
2022-04-06 02:41:32 +02:00
|
|
|
import org.assertj.core.description.Description;
|
|
|
|
import org.assertj.core.description.TextDescription;
|
2021-10-14 15:55:58 +02:00
|
|
|
import org.junit.jupiter.api.AfterEach;
|
|
|
|
import org.junit.jupiter.api.Assertions;
|
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import reactor.core.publisher.Flux;
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
public class TestHugePqHitQueue {
|
2021-10-14 15:55:58 +02:00
|
|
|
|
|
|
|
public static final int NUM_HITS = 1024;
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private LLTempHugePqEnv env;
|
|
|
|
private SafeCloseable hugePqQueue;
|
2021-10-14 15:55:58 +02:00
|
|
|
|
|
|
|
private TestingPriorityQueue testingPriorityQueue;
|
|
|
|
|
|
|
|
protected static boolean lessThan(ScoreDoc hitA, ScoreDoc hitB) {
|
|
|
|
if (hitA.score == hitB.score) {
|
|
|
|
return hitA.doc > hitB.doc;
|
|
|
|
} else {
|
|
|
|
return hitA.score < hitB.score;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static int compareScoreDoc(ScoreDoc hitA, ScoreDoc hitB) {
|
|
|
|
if (hitA.score == hitB.score) {
|
|
|
|
if (hitA.doc == hitB.doc) {
|
|
|
|
return Integer.compare(hitA.shardIndex, hitB.shardIndex);
|
|
|
|
} else {
|
|
|
|
return Integer.compare(hitB.doc, hitA.doc);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Float.compare(hitA.score, hitB.score);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static void assertEqualsScoreDoc(Description description, ScoreDoc expected, ScoreDoc actual) {
|
|
|
|
org.assertj.core.api.Assertions.assertThat(toLLScoreDoc(expected)).as(description).isEqualTo(toLLScoreDoc(actual));
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void assertEqualsScoreDoc(List<ScoreDoc> expected, List<ScoreDoc> actual) {
|
|
|
|
var list1 = expected.iterator();
|
|
|
|
var list2 = actual.iterator();
|
2022-04-06 02:41:32 +02:00
|
|
|
Assertions.assertEquals(expected.size(), actual.size());
|
2021-10-14 15:55:58 +02:00
|
|
|
while (list1.hasNext() && list2.hasNext()) {
|
|
|
|
Assertions.assertFalse(lessThan(list1.next(), list2.next()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@BeforeEach
|
|
|
|
public void beforeEach() throws IOException {
|
2022-04-06 02:41:32 +02:00
|
|
|
this.env = new LLTempHugePqEnv();
|
|
|
|
var hugePqQueue = new HugePqPriorityQueue<ScoreDoc>(env, new HugePqCodec<>() {
|
2021-10-14 15:55:58 +02:00
|
|
|
|
|
|
|
@Override
|
2022-04-06 02:41:32 +02:00
|
|
|
public Buffer serialize(Function<Integer, Buffer> allocator, ScoreDoc data) {
|
2021-10-14 15:55:58 +02:00
|
|
|
var buf = allocator.apply(Float.BYTES + Integer.BYTES + Integer.BYTES);
|
2022-04-06 02:41:32 +02:00
|
|
|
buf.writerOffset(Float.BYTES + Integer.BYTES + Integer.BYTES);
|
2021-10-14 15:55:58 +02:00
|
|
|
setScore(buf, data.score);
|
|
|
|
setDoc(buf, data.doc);
|
|
|
|
setShardIndex(buf, data.shardIndex);
|
2022-04-06 02:41:32 +02:00
|
|
|
return buf;
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-04-06 02:41:32 +02:00
|
|
|
public ScoreDoc deserialize(Buffer buf) {
|
2021-10-14 15:55:58 +02:00
|
|
|
return new ScoreDoc(getDoc(buf), getScore(buf), getShardIndex(buf));
|
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static float getScore(Buffer hit) {
|
|
|
|
return HugePqCodec.getLexFloat(hit, 0, false);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static int getDoc(Buffer hit) {
|
|
|
|
return HugePqCodec.getLexInt(hit, Float.BYTES, true);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static int getShardIndex(Buffer hit) {
|
|
|
|
return HugePqCodec.getLexInt(hit, Float.BYTES + Integer.BYTES, false);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static void setScore(Buffer hit, float score) {
|
|
|
|
HugePqCodec.setLexFloat(hit, 0, false, score);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static void setDoc(Buffer hit, int doc) {
|
|
|
|
HugePqCodec.setLexInt(hit, Float.BYTES, true, doc);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
private static void setShardIndex(Buffer hit, int shardIndex) {
|
|
|
|
HugePqCodec.setLexInt(hit, Float.BYTES + Integer.BYTES, false, shardIndex);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
@Override
|
|
|
|
public ScoreDoc clone(ScoreDoc obj) {
|
|
|
|
return new ScoreDoc(obj.doc, obj.score, obj.shardIndex);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
});
|
2022-04-06 02:41:32 +02:00
|
|
|
this.hugePqQueue = hugePqQueue;
|
2021-10-14 15:55:58 +02:00
|
|
|
PriorityQueueAdaptor<ScoreDoc> hitQueue = new PriorityQueueAdaptor<>(new HitQueue(NUM_HITS, false));
|
2022-04-06 02:41:32 +02:00
|
|
|
Assertions.assertEquals(0, hugePqQueue.size());
|
2021-10-14 15:55:58 +02:00
|
|
|
Assertions.assertEquals(0, hitQueue.size());
|
2022-04-06 02:41:32 +02:00
|
|
|
this.testingPriorityQueue = new TestingPriorityQueue(hitQueue, hugePqQueue);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testNoOp() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testEmptyTop() {
|
|
|
|
Assertions.assertNull(testingPriorityQueue.top());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddSingle() {
|
|
|
|
var item = new ScoreDoc(0, 0, 0);
|
|
|
|
testingPriorityQueue.add(item);
|
2022-04-06 02:41:32 +02:00
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", testingPriorityQueue), item, testingPriorityQueue.top());
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddMulti() {
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var item = new ScoreDoc(i, i >> 1, -1);
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
}
|
2022-04-06 02:41:32 +02:00
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", testingPriorityQueue), new ScoreDoc(1, 0, -1), testingPriorityQueue.top());
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
2022-06-15 13:09:45 +02:00
|
|
|
@Test
|
|
|
|
public void testAddMultiRandom() {
|
|
|
|
var list = new ArrayList<Integer>(1000);
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var ri = ThreadLocalRandom.current().nextInt(0, 20);
|
|
|
|
list.add(ri);
|
|
|
|
var item = new ScoreDoc(ri, ri << 1, ri % 4);
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
}
|
|
|
|
list.sort(Comparator.reverseOrder());
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var top = list.remove(list.size() - 1);
|
|
|
|
assertEqualsScoreDoc(new TextDescription("%d value of %s", i, testingPriorityQueue), new ScoreDoc(top, top << 1, top % 4), testingPriorityQueue.pop());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-14 15:55:58 +02:00
|
|
|
@Test
|
|
|
|
public void testAddMultiClear() {
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var item = new ScoreDoc(i, i >> 1, -1);
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
}
|
|
|
|
testingPriorityQueue.clear();
|
|
|
|
Assertions.assertNull(testingPriorityQueue.top());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddRemove() {
|
|
|
|
var item = new ScoreDoc(0, 0, -1);
|
|
|
|
testingPriorityQueue.add(item);
|
|
|
|
testingPriorityQueue.remove(item);
|
|
|
|
Assertions.assertNull(testingPriorityQueue.top());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddRemoveNonexistent() {
|
|
|
|
var item = new ScoreDoc(0, 0, 0);
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
testingPriorityQueue.remove(new ScoreDoc(2, 0, 0));
|
2022-04-06 02:41:32 +02:00
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", testingPriorityQueue), item, testingPriorityQueue.top());
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddMultiRemove1() {
|
|
|
|
ScoreDoc toRemove = null;
|
|
|
|
ScoreDoc top = null;
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var item = new ScoreDoc(i, i >> 1, -1);
|
|
|
|
if (i == 1) {
|
|
|
|
toRemove = item;
|
|
|
|
} else if (i == 0) {
|
|
|
|
top = item;
|
|
|
|
}
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
}
|
|
|
|
testingPriorityQueue.removeUnsafe(toRemove);
|
2022-04-06 02:41:32 +02:00
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", testingPriorityQueue), top, testingPriorityQueue.top());
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testAddMultiRemove2() {
|
|
|
|
ScoreDoc toRemove = null;
|
|
|
|
ScoreDoc top = null;
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
var item = new ScoreDoc(i, i >> 1, -1);
|
|
|
|
if (i == 0) {
|
|
|
|
toRemove = item;
|
|
|
|
} else if (i == 1) {
|
|
|
|
top = item;
|
|
|
|
}
|
|
|
|
testingPriorityQueue.addUnsafe(item);
|
|
|
|
}
|
|
|
|
testingPriorityQueue.removeUnsafe(new ScoreDoc(0, 0, -1));
|
2022-04-06 02:41:32 +02:00
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", testingPriorityQueue), top, testingPriorityQueue.top());
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void testSort() {
|
|
|
|
var sortedNumbers = new ArrayList<ScoreDoc>();
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
|
|
sortedNumbers.add(new ScoreDoc(i, i >> 1, -1));
|
|
|
|
}
|
2022-04-06 02:41:32 +02:00
|
|
|
sortedNumbers.sort(TestHugePqHitQueue::compareScoreDoc);
|
2021-10-14 15:55:58 +02:00
|
|
|
var shuffledNumbers = new ArrayList<>(sortedNumbers);
|
|
|
|
Collections.shuffle(shuffledNumbers, new Random(1000));
|
2022-04-06 02:41:32 +02:00
|
|
|
|
|
|
|
org.assertj.core.api.Assertions.assertThat(testingPriorityQueue.size()).isEqualTo(0);
|
|
|
|
|
2021-10-14 15:55:58 +02:00
|
|
|
for (ScoreDoc scoreDoc : shuffledNumbers) {
|
|
|
|
testingPriorityQueue.addUnsafe(scoreDoc);
|
|
|
|
}
|
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
org.assertj.core.api.Assertions.assertThat(testingPriorityQueue.size()).isEqualTo(sortedNumbers.size());
|
|
|
|
|
2021-10-14 15:55:58 +02:00
|
|
|
var newSortedNumbers = new ArrayList<ScoreDoc>();
|
|
|
|
ScoreDoc popped;
|
|
|
|
while ((popped = testingPriorityQueue.popUnsafe()) != null) {
|
|
|
|
newSortedNumbers.add(popped);
|
|
|
|
}
|
2022-04-06 02:41:32 +02:00
|
|
|
org.assertj.core.api.Assertions.assertThat(testingPriorityQueue.size()).isEqualTo(0);
|
2021-10-14 15:55:58 +02:00
|
|
|
|
|
|
|
assertEqualsScoreDoc(sortedNumbers, newSortedNumbers);
|
|
|
|
}
|
|
|
|
|
|
|
|
@AfterEach
|
|
|
|
public void afterEach() throws IOException {
|
2022-04-06 02:41:32 +02:00
|
|
|
hugePqQueue.close();
|
2021-10-14 15:55:58 +02:00
|
|
|
env.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class TestingPriorityQueue implements PriorityQueue<ScoreDoc> {
|
|
|
|
|
|
|
|
private final PriorityQueue<ScoreDoc> referenceQueue;
|
2022-04-06 02:41:32 +02:00
|
|
|
private final PriorityQueue<ScoreDoc> myQueue;
|
2021-10-14 15:55:58 +02:00
|
|
|
|
2022-04-06 02:41:32 +02:00
|
|
|
public TestingPriorityQueue(PriorityQueue<ScoreDoc> referenceQueue, PriorityQueue<ScoreDoc> myQueue) {
|
2021-10-14 15:55:58 +02:00
|
|
|
this.referenceQueue = referenceQueue;
|
2022-04-06 02:41:32 +02:00
|
|
|
this.myQueue = myQueue;
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void add(ScoreDoc element) {
|
|
|
|
referenceQueue.add(element);
|
2022-04-06 02:41:32 +02:00
|
|
|
myQueue.add(element);
|
2021-10-14 15:55:58 +02:00
|
|
|
ensureEquality();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addUnsafe(ScoreDoc element) {
|
|
|
|
referenceQueue.add(element);
|
2022-04-06 02:41:32 +02:00
|
|
|
myQueue.add(element);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ScoreDoc top() {
|
|
|
|
var top1 = referenceQueue.top();
|
2022-04-06 02:41:32 +02:00
|
|
|
var top2 = myQueue.top();
|
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", myQueue), top1, top2);
|
2021-10-14 15:55:58 +02:00
|
|
|
return top2;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ScoreDoc topUnsafe() {
|
|
|
|
var top1 = referenceQueue.top();
|
2022-04-06 02:41:32 +02:00
|
|
|
var top2 = myQueue.top();
|
2021-10-14 15:55:58 +02:00
|
|
|
return top2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ScoreDoc pop() {
|
|
|
|
var top1 = referenceQueue.pop();
|
2022-04-06 02:41:32 +02:00
|
|
|
var top2 = myQueue.pop();
|
|
|
|
assertEqualsScoreDoc(new TextDescription("top value of %s", myQueue), top1, top2);
|
2021-10-14 15:55:58 +02:00
|
|
|
return top2;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ScoreDoc popUnsafe() {
|
|
|
|
var top1 = referenceQueue.pop();
|
2022-04-06 02:41:32 +02:00
|
|
|
var top2 = myQueue.pop();
|
2021-10-14 15:55:58 +02:00
|
|
|
return top2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2022-06-15 18:36:22 +02:00
|
|
|
public void replaceTop(ScoreDoc oldTop, ScoreDoc newTop) {
|
|
|
|
referenceQueue.replaceTop(oldTop, newTop);
|
|
|
|
myQueue.replaceTop(oldTop, newTop);
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long size() {
|
|
|
|
var size1 = referenceQueue.size();
|
2022-04-06 02:41:32 +02:00
|
|
|
var size2 = myQueue.size();
|
2021-10-14 15:55:58 +02:00
|
|
|
Assertions.assertEquals(size1, size2);
|
|
|
|
return size2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void clear() {
|
|
|
|
referenceQueue.clear();
|
2022-04-06 02:41:32 +02:00
|
|
|
myQueue.clear();
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean remove(ScoreDoc element) {
|
2022-04-06 02:41:32 +02:00
|
|
|
var removedRef = referenceQueue.remove(element);
|
|
|
|
var removedMy = myQueue.remove(element);
|
|
|
|
Assertions.assertEquals(removedRef, removedMy);
|
|
|
|
return removedMy;
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean removeUnsafe(ScoreDoc element) {
|
|
|
|
var removed1 = referenceQueue.remove(element);
|
2022-04-06 02:41:32 +02:00
|
|
|
var removed2 = myQueue.remove(element);
|
2021-10-14 15:55:58 +02:00
|
|
|
return removed2;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Flux<ScoreDoc> iterate() {
|
|
|
|
//noinspection BlockingMethodInNonBlockingContext
|
|
|
|
var it1 = referenceQueue.iterate().collectList().blockOptional().orElseThrow();
|
|
|
|
//noinspection BlockingMethodInNonBlockingContext
|
2022-04-06 02:41:32 +02:00
|
|
|
var it2 = myQueue.iterate().collectList().blockOptional().orElseThrow();
|
2021-10-14 15:55:58 +02:00
|
|
|
assertEqualsScoreDoc(it1, it2);
|
|
|
|
return Flux.fromIterable(it2);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-12-18 21:01:14 +01:00
|
|
|
public void close() {
|
|
|
|
referenceQueue.close();
|
2022-04-06 02:41:32 +02:00
|
|
|
myQueue.close();
|
2021-10-14 15:55:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private void ensureEquality() {
|
2022-04-06 02:41:32 +02:00
|
|
|
Assertions.assertEquals(referenceQueue.size(), myQueue.size());
|
2021-10-14 15:55:58 +02:00
|
|
|
var referenceQueueElements = Lists.newArrayList(referenceQueue
|
|
|
|
.iterate()
|
2022-04-06 02:41:32 +02:00
|
|
|
.map(TestHugePqHitQueue::toLLScoreDoc)
|
2021-10-14 15:55:58 +02:00
|
|
|
.toIterable());
|
2022-04-06 02:41:32 +02:00
|
|
|
var testQueueElements = Lists.newArrayList(myQueue
|
2021-10-14 15:55:58 +02:00
|
|
|
.iterate()
|
2022-04-06 02:41:32 +02:00
|
|
|
.map(TestHugePqHitQueue::toLLScoreDoc)
|
2021-10-14 15:55:58 +02:00
|
|
|
.toIterable());
|
|
|
|
Assertions.assertEquals(referenceQueueElements, testQueueElements);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static LLScoreDoc toLLScoreDoc(ScoreDoc scoreDoc) {
|
|
|
|
if (scoreDoc == null) return null;
|
|
|
|
return new LLScoreDoc(scoreDoc.doc, scoreDoc.score, scoreDoc.shardIndex);
|
|
|
|
}
|
|
|
|
}
|