LUCENE-8750: Add setMissingValue to sorts from Double/LongValuesSource

This commit is contained in:
Alan Woodward 2019-04-03 09:42:36 +01:00
parent a248bc209e
commit 6f47062a9b
5 changed files with 120 additions and 11 deletions

View File

@ -70,6 +70,9 @@ Improvements
* LUCENE-8732: ConstantScoreQuery can now early terminate the query if the minimum score is * LUCENE-8732: ConstantScoreQuery can now early terminate the query if the minimum score is
greater than the constant score and total hits are not requested. (Jim Ferenczi) greater than the constant score and total hits are not requested. (Jim Ferenczi)
* LUCENE-8750: Implements setMissingValue() on sort fields produced from
DoubleValuesSource and LongValuesSource (Mike Sokolov via Alan Woodward)
Changes in Runtime Behavior Changes in Runtime Behavior
* LUCENE-8671: Load FST off-heap also for ID-like fields if reader is not opened * LUCENE-8671: Load FST off-heap also for ID-like fields if reader is not opened

View File

@ -428,6 +428,16 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
this.producer = producer; this.producer = producer;
} }
@Override
public void setMissingValue(Object missingValue) {
if (missingValue instanceof Number) {
this.missingValue = missingValue;
((DoubleValuesComparatorSource) getComparatorSource()).setMissingValue(((Number) missingValue).doubleValue());
} else {
super.setMissingValue(missingValue);
}
}
@Override @Override
public boolean needsScores() { public boolean needsScores() {
return producer.needsScores(); return producer.needsScores();
@ -444,8 +454,13 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
@Override @Override
public SortField rewrite(IndexSearcher searcher) throws IOException { public SortField rewrite(IndexSearcher searcher) throws IOException {
return new DoubleValuesSortField(producer.rewrite(searcher), reverse); DoubleValuesSortField rewritten = new DoubleValuesSortField(producer.rewrite(searcher), reverse);
if (missingValue != null) {
rewritten.setMissingValue(missingValue);
}
return rewritten;
} }
} }
private static class DoubleValuesHolder { private static class DoubleValuesHolder {
@ -454,15 +469,21 @@ public abstract class DoubleValuesSource implements SegmentCacheable {
private static class DoubleValuesComparatorSource extends FieldComparatorSource { private static class DoubleValuesComparatorSource extends FieldComparatorSource {
private final DoubleValuesSource producer; private final DoubleValuesSource producer;
private double missingValue;
DoubleValuesComparatorSource(DoubleValuesSource producer) { DoubleValuesComparatorSource(DoubleValuesSource producer) {
this.producer = producer; this.producer = producer;
this.missingValue = 0d;
}
void setMissingValue(double missingValue) {
this.missingValue = missingValue;
} }
@Override @Override
public FieldComparator<Double> newComparator(String fieldname, int numHits, public FieldComparator<Double> newComparator(String fieldname, int numHits,
int sortPos, boolean reversed) { int sortPos, boolean reversed) {
return new FieldComparator.DoubleComparator(numHits, fieldname, 0.0){ return new FieldComparator.DoubleComparator(numHits, fieldname, missingValue){
LeafReaderContext ctx; LeafReaderContext ctx;
DoubleValuesHolder holder = new DoubleValuesHolder(); DoubleValuesHolder holder = new DoubleValuesHolder();

View File

@ -279,6 +279,16 @@ public abstract class LongValuesSource implements SegmentCacheable {
this.producer = producer; this.producer = producer;
} }
@Override
public void setMissingValue(Object missingValue) {
if (missingValue instanceof Number) {
this.missingValue = missingValue;
((LongValuesComparatorSource) getComparatorSource()).setMissingValue(((Number) missingValue).longValue());
} else {
super.setMissingValue(missingValue);
}
}
@Override @Override
public boolean needsScores() { public boolean needsScores() {
return producer.needsScores(); return producer.needsScores();
@ -295,7 +305,11 @@ public abstract class LongValuesSource implements SegmentCacheable {
@Override @Override
public SortField rewrite(IndexSearcher searcher) throws IOException { public SortField rewrite(IndexSearcher searcher) throws IOException {
return new LongValuesSortField(producer.rewrite(searcher), reverse); LongValuesSortField rewritten = new LongValuesSortField(producer.rewrite(searcher), reverse);
if (missingValue != null) {
rewritten.setMissingValue(missingValue);
}
return rewritten;
} }
} }
@ -305,15 +319,21 @@ public abstract class LongValuesSource implements SegmentCacheable {
private static class LongValuesComparatorSource extends FieldComparatorSource { private static class LongValuesComparatorSource extends FieldComparatorSource {
private final LongValuesSource producer; private final LongValuesSource producer;
private long missingValue;
public LongValuesComparatorSource(LongValuesSource producer) { public LongValuesComparatorSource(LongValuesSource producer) {
this.producer = producer; this.producer = producer;
this.missingValue = 0L;
}
void setMissingValue(long missingValue) {
this.missingValue = missingValue;
} }
@Override @Override
public FieldComparator<Long> newComparator(String fieldname, int numHits, public FieldComparator<Long> newComparator(String fieldname, int numHits,
int sortPos, boolean reversed) { int sortPos, boolean reversed) {
return new FieldComparator.LongComparator(numHits, fieldname, 0L){ return new FieldComparator.LongComparator(numHits, fieldname, missingValue) {
LeafReaderContext ctx; LeafReaderContext ctx;
LongValuesHolder holder = new LongValuesHolder(); LongValuesHolder holder = new LongValuesHolder();

View File

@ -38,6 +38,8 @@ import org.apache.lucene.util.TestUtil;
public class TestDoubleValuesSource extends LuceneTestCase { public class TestDoubleValuesSource extends LuceneTestCase {
private static final double LEAST_DOUBLE_VALUE = 45.72;
private Directory dir; private Directory dir;
private IndexReader reader; private IndexReader reader;
private IndexSearcher searcher; private IndexSearcher searcher;
@ -57,7 +59,7 @@ public class TestDoubleValuesSource extends LuceneTestCase {
document.add(new FloatDocValuesField("float", random().nextFloat())); document.add(new FloatDocValuesField("float", random().nextFloat()));
document.add(new DoubleDocValuesField("double", random().nextDouble())); document.add(new DoubleDocValuesField("double", random().nextDouble()));
if (i == 545) if (i == 545)
document.add(new DoubleDocValuesField("onefield", 45.72)); document.add(new DoubleDocValuesField("onefield", LEAST_DOUBLE_VALUE));
iw.addDocument(document); iw.addDocument(document);
} }
reader = iw.getReader(); reader = iw.getReader();
@ -72,11 +74,41 @@ public class TestDoubleValuesSource extends LuceneTestCase {
super.tearDown(); super.tearDown();
} }
public void testSortMissing() throws Exception { public void testSortMissingZeroDefault() throws Exception {
// docs w/no value get default missing value = 0
DoubleValuesSource onefield = DoubleValuesSource.fromDoubleField("onefield"); DoubleValuesSource onefield = DoubleValuesSource.fromDoubleField("onefield");
// sort decreasing
TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(true))); TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(true)));
FieldDoc first = (FieldDoc) results.scoreDocs[0]; FieldDoc first = (FieldDoc) results.scoreDocs[0];
assertEquals(45.72, first.fields[0]); assertEquals(LEAST_DOUBLE_VALUE, first.fields[0]);
// sort increasing
results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(false)));
first = (FieldDoc) results.scoreDocs[0];
assertEquals(0d, first.fields[0]);
}
public void testSortMissingExplicit() throws Exception {
// docs w/no value get provided missing value
DoubleValuesSource onefield = DoubleValuesSource.fromDoubleField("onefield");
// sort decreasing, missing last
SortField oneFieldSort = onefield.getSortField(true);
oneFieldSort.setMissingValue(Double.MIN_VALUE);
TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(oneFieldSort));
FieldDoc first = (FieldDoc) results.scoreDocs[0];
assertEquals(LEAST_DOUBLE_VALUE, first.fields[0]);
// sort increasing, missing last
oneFieldSort = onefield.getSortField(false);
oneFieldSort.setMissingValue(Double.MAX_VALUE);
results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(oneFieldSort));
first = (FieldDoc) results.scoreDocs[0];
assertEquals(LEAST_DOUBLE_VALUE, first.fields[0]);
} }
public void testSimpleFieldEquivalences() throws Exception { public void testSimpleFieldEquivalences() throws Exception {

View File

@ -34,6 +34,8 @@ import org.apache.lucene.util.TestUtil;
public class TestLongValuesSource extends LuceneTestCase { public class TestLongValuesSource extends LuceneTestCase {
private static final long LEAST_LONG_VALUE = 45L;
private Directory dir; private Directory dir;
private IndexReader reader; private IndexReader reader;
private IndexSearcher searcher; private IndexSearcher searcher;
@ -44,6 +46,7 @@ public class TestLongValuesSource extends LuceneTestCase {
dir = newDirectory(); dir = newDirectory();
RandomIndexWriter iw = new RandomIndexWriter(random(), dir); RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
int numDocs = TestUtil.nextInt(random(), 2049, 4000); int numDocs = TestUtil.nextInt(random(), 2049, 4000);
int leastValue = 45;
for (int i = 0; i < numDocs; i++) { for (int i = 0; i < numDocs; i++) {
Document document = new Document(); Document document = new Document();
document.add(newTextField("english", English.intToEnglish(i), Field.Store.NO)); document.add(newTextField("english", English.intToEnglish(i), Field.Store.NO));
@ -51,7 +54,7 @@ public class TestLongValuesSource extends LuceneTestCase {
document.add(new NumericDocValuesField("int", random().nextInt())); document.add(new NumericDocValuesField("int", random().nextInt()));
document.add(new NumericDocValuesField("long", random().nextLong())); document.add(new NumericDocValuesField("long", random().nextLong()));
if (i == 545) if (i == 545)
document.add(new NumericDocValuesField("onefield", 45)); document.add(new NumericDocValuesField("onefield", LEAST_LONG_VALUE));
iw.addDocument(document); iw.addDocument(document);
} }
reader = iw.getReader(); reader = iw.getReader();
@ -66,11 +69,41 @@ public class TestLongValuesSource extends LuceneTestCase {
super.tearDown(); super.tearDown();
} }
public void testSortMissing() throws Exception { public void testSortMissingZeroDefault() throws Exception {
// docs w/no value get default missing value = 0
LongValuesSource onefield = LongValuesSource.fromLongField("onefield"); LongValuesSource onefield = LongValuesSource.fromLongField("onefield");
// sort decreasing
TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(true))); TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(true)));
FieldDoc first = (FieldDoc) results.scoreDocs[0]; FieldDoc first = (FieldDoc) results.scoreDocs[0];
assertEquals(45L, first.fields[0]); assertEquals(LEAST_LONG_VALUE, first.fields[0]);
// sort increasing
results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(onefield.getSortField(false)));
first = (FieldDoc) results.scoreDocs[0];
assertEquals(0L, first.fields[0]);
}
public void testSortMissingExplicit() throws Exception {
// docs w/no value get provided missing value
LongValuesSource onefield = LongValuesSource.fromLongField("onefield");
// sort decreasing, missing last
SortField oneFieldSort = onefield.getSortField(true);
oneFieldSort.setMissingValue(Long.MIN_VALUE);
TopDocs results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(oneFieldSort));
FieldDoc first = (FieldDoc) results.scoreDocs[0];
assertEquals(LEAST_LONG_VALUE, first.fields[0]);
// sort increasing, missing last
oneFieldSort = onefield.getSortField(false);
oneFieldSort.setMissingValue(Long.MAX_VALUE);
results = searcher.search(new MatchAllDocsQuery(), 1, new Sort(oneFieldSort));
first = (FieldDoc) results.scoreDocs[0];
assertEquals(LEAST_LONG_VALUE, first.fields[0]);
} }
public void testSimpleFieldEquivalences() throws Exception { public void testSimpleFieldEquivalences() throws Exception {