mirror of https://github.com/apache/lucene.git
LUCENE-7847: Fix the all-docs-match optimization of range queries on range fields.
This commit is contained in:
parent
31e02e93a5
commit
14320a584c
|
@ -155,6 +155,9 @@ Bug Fixes
|
|||
* LUCENE-7833: ToParentBlockJoinQuery computed the min score instead of the max
|
||||
score with ScoreMode.MAX. (Adrien Grand)
|
||||
|
||||
* LUCENE-7847: Fixed all-docs-match optimization of range queries on range
|
||||
fields. (Adrien Grand)
|
||||
|
||||
Improvements
|
||||
|
||||
* LUCENE-7782: OfflineSorter now passes the total number of items it
|
||||
|
|
|
@ -112,6 +112,7 @@ abstract class RangeFieldQuery extends Query {
|
|||
public final Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
|
||||
return new ConstantScoreWeight(this, boost) {
|
||||
final RangeFieldComparator target = new RangeFieldComparator();
|
||||
|
||||
private DocIdSet buildMatchingDocIdSet(LeafReader reader, PointValues values) throws IOException {
|
||||
DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
|
||||
values.intersect(
|
||||
|
@ -133,25 +134,29 @@ abstract class RangeFieldQuery extends Query {
|
|||
}
|
||||
@Override
|
||||
public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
|
||||
byte[] node = getInternalRange(minPackedValue, maxPackedValue);
|
||||
// compute range relation for BKD traversal
|
||||
if (target.intersects(node) == false) {
|
||||
return Relation.CELL_OUTSIDE_QUERY;
|
||||
} else if (target.within(node)) {
|
||||
// target within cell; continue traversing:
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
} else if (target.contains(node)) {
|
||||
// target contains cell; add iff queryType is not a CONTAINS or CROSSES query:
|
||||
return (queryType == QueryType.CONTAINS || queryType == QueryType.CROSSES) ?
|
||||
Relation.CELL_OUTSIDE_QUERY : Relation.CELL_INSIDE_QUERY;
|
||||
}
|
||||
// target intersects cell; continue traversing:
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
return compareRange(minPackedValue, maxPackedValue);
|
||||
}
|
||||
});
|
||||
return result.build();
|
||||
}
|
||||
|
||||
private Relation compareRange(byte[] minPackedValue, byte[] maxPackedValue) {
|
||||
byte[] node = getInternalRange(minPackedValue, maxPackedValue);
|
||||
// compute range relation for BKD traversal
|
||||
if (target.intersects(node) == false) {
|
||||
return Relation.CELL_OUTSIDE_QUERY;
|
||||
} else if (target.within(node)) {
|
||||
// target within cell; continue traversing:
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
} else if (target.contains(node)) {
|
||||
// target contains cell; add iff queryType is not a CONTAINS or CROSSES query:
|
||||
return (queryType == QueryType.CONTAINS || queryType == QueryType.CROSSES) ?
|
||||
Relation.CELL_OUTSIDE_QUERY : Relation.CELL_INSIDE_QUERY;
|
||||
}
|
||||
// target intersects cell; continue traversing:
|
||||
return Relation.CELL_CROSSES_QUERY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scorer scorer(LeafReaderContext context) throws IOException {
|
||||
LeafReader reader = context.reader();
|
||||
|
@ -166,17 +171,10 @@ abstract class RangeFieldQuery extends Query {
|
|||
return null;
|
||||
}
|
||||
checkFieldInfo(fieldInfo);
|
||||
boolean allDocsMatch = true;
|
||||
if (values.getDocCount() == reader.maxDoc()) {
|
||||
// if query crosses, docs need to be further scrutinized
|
||||
byte[] range = getInternalRange(values.getMinPackedValue(), values.getMaxPackedValue());
|
||||
// if the internal node is not equal and not contained by the query, all docs do not match
|
||||
if (queryType == QueryType.CROSSES || (!Arrays.equals(ranges, range)
|
||||
&& (target.contains(range) == false || queryType != QueryType.WITHIN))) {
|
||||
allDocsMatch = false;
|
||||
}
|
||||
} else {
|
||||
allDocsMatch = false;
|
||||
boolean allDocsMatch = false;
|
||||
if (values.getDocCount() == reader.maxDoc()
|
||||
&& compareRange(values.getMinPackedValue(), values.getMaxPackedValue()) == Relation.CELL_INSIDE_QUERY) {
|
||||
allDocsMatch = true;
|
||||
}
|
||||
|
||||
DocIdSetIterator iterator = allDocsMatch == true ?
|
||||
|
|
|
@ -31,11 +31,18 @@ public class TestDoubleRangeFieldQueries extends BaseRangeFieldQueryTestCase {
|
|||
private static final String FIELD_NAME = "doubleRangeField";
|
||||
|
||||
private double nextDoubleInternal() {
|
||||
if (rarely()) {
|
||||
return random().nextBoolean() ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
|
||||
switch (random().nextInt(5)) {
|
||||
case 0:
|
||||
return Double.NEGATIVE_INFINITY;
|
||||
case 1:
|
||||
return Double.POSITIVE_INFINITY;
|
||||
default:
|
||||
if (random().nextBoolean()) {
|
||||
return random().nextDouble();
|
||||
} else {
|
||||
return (random().nextInt(15) - 7) / 3d;
|
||||
}
|
||||
}
|
||||
double max = Double.MAX_VALUE / 2;
|
||||
return (max + max) * random().nextDouble() - max;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,11 +31,18 @@ public class TestFloatRangeFieldQueries extends BaseRangeFieldQueryTestCase {
|
|||
private static final String FIELD_NAME = "floatRangeField";
|
||||
|
||||
private float nextFloatInternal() {
|
||||
if (rarely()) {
|
||||
return random().nextBoolean() ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
|
||||
switch (random().nextInt(5)) {
|
||||
case 0:
|
||||
return Float.NEGATIVE_INFINITY;
|
||||
case 1:
|
||||
return Float.POSITIVE_INFINITY;
|
||||
default:
|
||||
if (random().nextBoolean()) {
|
||||
return random().nextFloat();
|
||||
} else {
|
||||
return (random().nextInt(15) - 7) / 3f;
|
||||
}
|
||||
}
|
||||
float max = Float.MAX_VALUE / 2;
|
||||
return (max + max) * random().nextFloat() - max;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.document.IntRange;
|
|||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.TestUtil;
|
||||
|
||||
/**
|
||||
* Random testing for IntRange Queries.
|
||||
|
@ -31,11 +32,25 @@ public class TestIntRangeFieldQueries extends BaseRangeFieldQueryTestCase {
|
|||
private static final String FIELD_NAME = "intRangeField";
|
||||
|
||||
private int nextIntInternal() {
|
||||
if (rarely()) {
|
||||
return random().nextBoolean() ? Integer.MAX_VALUE : Integer.MIN_VALUE;
|
||||
switch (random().nextInt(5)) {
|
||||
case 0:
|
||||
return Integer.MIN_VALUE;
|
||||
case 1:
|
||||
return Integer.MAX_VALUE;
|
||||
default:
|
||||
int bpv = random().nextInt(32);
|
||||
switch (bpv) {
|
||||
case 32:
|
||||
return random().nextInt();
|
||||
default:
|
||||
int v = TestUtil.nextInt(random(), 0, (1 << bpv) - 1);
|
||||
if (bpv > 0) {
|
||||
// negative values sometimes
|
||||
v -= 1 << (bpv - 1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
int max = Integer.MAX_VALUE / 2;
|
||||
return (max + max) * random().nextInt() - max;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.apache.lucene.document.LongRange;
|
|||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.RandomIndexWriter;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.TestUtil;
|
||||
|
||||
/**
|
||||
* Random testing for LongRange Queries.
|
||||
|
@ -31,11 +32,25 @@ public class TestLongRangeFieldQueries extends BaseRangeFieldQueryTestCase {
|
|||
private static final String FIELD_NAME = "longRangeField";
|
||||
|
||||
private long nextLongInternal() {
|
||||
if (rarely()) {
|
||||
return random().nextBoolean() ? Long.MAX_VALUE : Long.MIN_VALUE;
|
||||
switch (random().nextInt(5)) {
|
||||
case 0:
|
||||
return Long.MIN_VALUE;
|
||||
case 1:
|
||||
return Long.MAX_VALUE;
|
||||
default:
|
||||
int bpv = random().nextInt(64);
|
||||
switch (bpv) {
|
||||
case 64:
|
||||
return random().nextLong();
|
||||
default:
|
||||
long v = TestUtil.nextLong(random(), 0, (1L << bpv) - 1);
|
||||
if (bpv > 0) {
|
||||
// negative values sometimes
|
||||
v -= 1L << (bpv - 1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
long max = Long.MAX_VALUE / 2;
|
||||
return (max + max) * random().nextLong() - max;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.apache.lucene.search;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.lucene.document.InetAddressPoint;
|
||||
import org.apache.lucene.document.InetAddressRange;
|
||||
|
@ -44,8 +45,19 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
|
|||
/** return random IPv4 or IPv6 address */
|
||||
private InetAddress nextInetaddress() throws UnknownHostException {
|
||||
byte[] b = random().nextBoolean() ? new byte[4] : new byte[16];
|
||||
random().nextBytes(b);
|
||||
return InetAddress.getByAddress(b);
|
||||
switch (random().nextInt(5)) {
|
||||
case 0:
|
||||
return InetAddress.getByAddress(b);
|
||||
case 1:
|
||||
Arrays.fill(b, (byte) 0xff);
|
||||
return InetAddress.getByAddress(b);
|
||||
case 2:
|
||||
Arrays.fill(b, (byte) 42);
|
||||
return InetAddress.getByAddress(b);
|
||||
default:
|
||||
random().nextBytes(b);
|
||||
return InetAddress.getByAddress(b);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -159,7 +171,7 @@ public class TestInetAddressRangeQueries extends BaseRangeFieldQueryTestCase {
|
|||
@Override
|
||||
protected boolean isEqual(Range o) {
|
||||
IpRange other = (IpRange)o;
|
||||
return this.min.equals(other.min) && this.max.equals(other.max);
|
||||
return Arrays.equals(min, other.min) && Arrays.equals(max, other.max);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -61,7 +61,9 @@ public abstract class BaseRangeFieldQueryTestCase extends LuceneTestCase {
|
|||
|
||||
public void testRandomTiny() throws Exception {
|
||||
// Make sure single-leaf-node case is OK:
|
||||
doTestRandom(10, false);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
doTestRandom(10, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void testRandomMedium() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue