Integrate IndexOrDocValuesQuery. (#23119)

This gives Lucene the choice to use index/point-based queries or
doc-values-based queries depending on which one is more efficient. This commit
integrates this feature for:
 - long/integer/short/byte/double/float/half_float/scaled_float ranges,
 - date ranges,
 - geo bounding box queries,
 - geo distance queries.
This commit is contained in:
Adrien Grand 2017-02-14 15:57:12 +01:00 committed by GitHub
parent 12bbe6e660
commit a969dad43e
15 changed files with 268 additions and 79 deletions

View File

@ -28,6 +28,7 @@ import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.action.fieldstats.FieldStats;
@ -285,7 +286,12 @@ public class DateFieldMapper extends FieldMapper {
--u;
}
}
return LongPoint.newRangeQuery(name(), l, u);
Query query = LongPoint.newRangeQuery(name(), l, u);
if (hasDocValues()) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(name(), l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
public long parseToMilliseconds(Object value, boolean roundUp,

View File

@ -33,6 +33,7 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.PointValues;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
@ -190,7 +191,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
float l = Float.NEGATIVE_INFINITY;
float u = Float.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -207,7 +209,14 @@ public class NumberFieldMapper extends FieldMapper {
}
u = HalfFloatPoint.nextDown(u);
}
return HalfFloatPoint.newRangeQuery(field, l, u);
Query query = HalfFloatPoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field,
HalfFloatPoint.halfFloatToSortableShort(l),
HalfFloatPoint.halfFloatToSortableShort(u));
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override
@ -280,7 +289,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
float l = Float.NEGATIVE_INFINITY;
float u = Float.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -295,7 +305,14 @@ public class NumberFieldMapper extends FieldMapper {
u = FloatPoint.nextDown(u);
}
}
return FloatPoint.newRangeQuery(field, l, u);
Query query = FloatPoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field,
NumericUtils.floatToSortableInt(l),
NumericUtils.floatToSortableInt(u));
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override
@ -368,7 +385,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
double l = Double.NEGATIVE_INFINITY;
double u = Double.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -383,7 +401,14 @@ public class NumberFieldMapper extends FieldMapper {
u = DoublePoint.nextDown(u);
}
}
return DoublePoint.newRangeQuery(field, l, u);
Query query = DoublePoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field,
NumericUtils.doubleToSortableLong(l),
NumericUtils.doubleToSortableLong(u));
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override
@ -462,8 +487,9 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper);
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues);
}
@Override
@ -523,8 +549,9 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper);
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues);
}
@Override
@ -600,7 +627,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
int l = Integer.MIN_VALUE;
int u = Integer.MAX_VALUE;
if (lowerTerm != null) {
@ -630,7 +658,12 @@ public class NumberFieldMapper extends FieldMapper {
--u;
}
}
return IntPoint.newRangeQuery(field, l, u);
Query query = IntPoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field, l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override
@ -724,7 +757,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
long l = Long.MIN_VALUE;
long u = Long.MAX_VALUE;
if (lowerTerm != null) {
@ -754,7 +788,12 @@ public class NumberFieldMapper extends FieldMapper {
--u;
}
}
return LongPoint.newRangeQuery(field, l, u);
Query query = LongPoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newRangeQuery(field, l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override
@ -812,7 +851,8 @@ public class NumberFieldMapper extends FieldMapper {
abstract Query termQuery(String field, Object value);
abstract Query termsQuery(String field, List<Object> values);
abstract Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper);
boolean includeLower, boolean includeUpper,
boolean hasDocValues);
abstract Number parse(XContentParser parser, boolean coerce) throws IOException;
abstract Number parse(Object value, boolean coerce);
public abstract List<Field> createFields(String name, Number value, boolean indexed,
@ -906,7 +946,7 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower, boolean includeUpper, QueryShardContext context) {
failIfNotIndexed();
Query query = type.rangeQuery(name(), lowerTerm, upperTerm, includeLower, includeUpper);
Query query = type.rangeQuery(name(), lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues());
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}

View File

@ -251,7 +251,7 @@ public class ScaledFloatFieldMapper extends FieldMapper {
}
hi = Math.round(Math.floor(dValue * scalingFactor));
}
Query query = NumberFieldMapper.NumberType.LONG.rangeQuery(name(), lo, hi, true, true);
Query query = NumberFieldMapper.NumberType.LONG.rangeQuery(name(), lo, hi, true, true, hasDocValues());
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}

View File

@ -19,8 +19,10 @@
package org.elasticsearch.index.query;
import org.apache.lucene.document.LatLonDocValuesField;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.geo.Rectangle;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchParseException;
@ -348,8 +350,15 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding
}
}
return LatLonPoint.newBoxQuery(fieldType.name(), luceneBottomRight.getLat(), luceneTopLeft.getLat(),
Query query = LatLonPoint.newBoxQuery(fieldType.name(), luceneBottomRight.getLat(), luceneTopLeft.getLat(),
luceneTopLeft.getLon(), luceneBottomRight.getLon());
if (fieldType.hasDocValues()) {
Query dvQuery = LatLonDocValuesField.newBoxQuery(fieldType.name(),
luceneBottomRight.getLat(), luceneTopLeft.getLat(),
luceneTopLeft.getLon(), luceneBottomRight.getLon());
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override

View File

@ -19,7 +19,9 @@
package org.elasticsearch.index.query;
import org.apache.lucene.document.LatLonDocValuesField;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
@ -249,7 +251,12 @@ public class GeoDistanceQueryBuilder extends AbstractQueryBuilder<GeoDistanceQue
GeoUtils.normalizePoint(center, true, true);
}
return LatLonPoint.newDistanceQuery(fieldType.name(), center.lat(), center.lon(), this.distance);
Query query = LatLonPoint.newDistanceQuery(fieldType.name(), center.lat(), center.lon(), this.distance);
if (fieldType.hasDocValues()) {
Query dvQuery = LatLonDocValuesField.newDistanceQuery(fieldType.name(), center.lat(), center.lon(), this.distance);
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
}
@Override

View File

@ -19,12 +19,15 @@
package org.elasticsearch.index.mapper;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.Version;
@ -172,7 +175,10 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
String date = "2015-10-12T14:10:55";
long instant = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parser().parseDateTime(date).getMillis();
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", instant, instant + 999), ft.termQuery(date, context));
Query expected = new IndexOrDocValuesQuery(
LongPoint.newRangeQuery("field", instant, instant + 999),
SortedNumericDocValuesField.newRangeQuery("field", instant, instant + 999));
assertEquals(expected, ft.termQuery(date, context));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
@ -193,7 +199,10 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
long instant1 = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parser().parseDateTime(date1).getMillis();
long instant2 = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parser().parseDateTime(date2).getMillis() + 999;
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", instant1, instant2),
Query expected = new IndexOrDocValuesQuery(
LongPoint.newRangeQuery("field", instant1, instant2),
SortedNumericDocValuesField.newRangeQuery("field", instant1, instant2));
assertEquals(expected,
ft.rangeQuery(date1, date2, true, true, context).rewrite(new MultiReader()));
ft.setIndexOptions(IndexOptions.NONE);

View File

@ -25,21 +25,26 @@ import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.HalfFloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.hamcrest.Matchers;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.function.Supplier;
public class NumberFieldTypeTests extends FieldTypeTestCase {
@ -124,83 +129,86 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
MappedFieldType ftInt = new NumberFieldMapper.NumberFieldType(NumberType.INTEGER);
ftInt.setName("field");
ftInt.setIndexOptions(IndexOptions.DOCS);
assertEquals(IntPoint.newRangeQuery("field", -3, -3), ftInt.rangeQuery(-3.5, -2.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", -3, -3), ftInt.rangeQuery(-3.5, -2.5, false, false, null));
assertEquals(IntPoint.newRangeQuery("field", 0, 0), ftInt.rangeQuery(-0.5, 0.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 0, 0), ftInt.rangeQuery(-0.5, 0.5, false, false, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 2), ftInt.rangeQuery(0.5, 2.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 2), ftInt.rangeQuery(0.5, 2.5, false, false, null));
assertEquals(IntPoint.newRangeQuery("field", 0, 2), ftInt.rangeQuery(-0.5, 2.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 0, 2), ftInt.rangeQuery(-0.5, 2.5, false, false, null));
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null), ftInt.rangeQuery(-3.5, -2.5, true, true, null));
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null), ftInt.rangeQuery(-3.5, -2.5, false, false, null));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null), ftInt.rangeQuery(-0.5, 0.5, true, true, null));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null), ftInt.rangeQuery(-0.5, 0.5, false, false, null));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null), ftInt.rangeQuery(0.5, 2.5, true, true, null));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null), ftInt.rangeQuery(0.5, 2.5, false, false, null));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null), ftInt.rangeQuery(-0.5, 2.5, true, true, null));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null), ftInt.rangeQuery(-0.5, 2.5, false, false, null));
assertEquals(IntPoint.newRangeQuery("field", -2, 0), ftInt.rangeQuery(-2.5, 0.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", -2, 0), ftInt.rangeQuery(-2.5, 0.5, false, false, null));
assertEquals(IntPoint.newRangeQuery("field", -2, -1), ftInt.rangeQuery(-2.5, -0.5, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", -2, -1), ftInt.rangeQuery(-2.5, -0.5, false, false, null));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null), ftInt.rangeQuery(-2.5, 0.5, true, true, null));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null), ftInt.rangeQuery(-2.5, 0.5, false, false, null));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null), ftInt.rangeQuery(-2.5, -0.5, true, true, null));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null), ftInt.rangeQuery(-2.5, -0.5, false, false, null));
MappedFieldType ftLong = new NumberFieldMapper.NumberFieldType(NumberType.LONG);
ftLong.setName("field");
ftLong.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", -3, -3), ftLong.rangeQuery(-3.5, -2.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", -3, -3), ftLong.rangeQuery(-3.5, -2.5, false, false, null));
assertEquals(LongPoint.newRangeQuery("field", 0, 0), ftLong.rangeQuery(-0.5, 0.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", 0, 0), ftLong.rangeQuery(-0.5, 0.5, false, false, null));
assertEquals(LongPoint.newRangeQuery("field", 1, 2), ftLong.rangeQuery(0.5, 2.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", 1, 2), ftLong.rangeQuery(0.5, 2.5, false, false, null));
assertEquals(LongPoint.newRangeQuery("field", 0, 2), ftLong.rangeQuery(-0.5, 2.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", 0, 2), ftLong.rangeQuery(-0.5, 2.5, false, false, null));
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null), ftLong.rangeQuery(-3.5, -2.5, true, true, null));
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null), ftLong.rangeQuery(-3.5, -2.5, false, false, null));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null), ftLong.rangeQuery(-0.5, 0.5, true, true, null));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null), ftLong.rangeQuery(-0.5, 0.5, false, false, null));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null), ftLong.rangeQuery(0.5, 2.5, true, true, null));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null), ftLong.rangeQuery(0.5, 2.5, false, false, null));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null), ftLong.rangeQuery(-0.5, 2.5, true, true, null));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null), ftLong.rangeQuery(-0.5, 2.5, false, false, null));
assertEquals(LongPoint.newRangeQuery("field", -2, 0), ftLong.rangeQuery(-2.5, 0.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", -2, 0), ftLong.rangeQuery(-2.5, 0.5, false, false, null));
assertEquals(LongPoint.newRangeQuery("field", -2, -1), ftLong.rangeQuery(-2.5, -0.5, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", -2, -1), ftLong.rangeQuery(-2.5, -0.5, false, false, null));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null), ftLong.rangeQuery(-2.5, 0.5, true, true, null));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null), ftLong.rangeQuery(-2.5, 0.5, false, false, null));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null), ftLong.rangeQuery(-2.5, -0.5, true, true, null));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null), ftLong.rangeQuery(-2.5, -0.5, false, false, null));
}
public void testByteRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.BYTE);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, false, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, false, null));
}
public void testShortRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.SHORT);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, false, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, false, null));
}
public void testIntegerRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.INTEGER);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(IntPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, false, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, false, null));
}
public void testLongRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.LONG);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", 2, 10), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(LongPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(LongPoint.newRangeQuery("field", 1, 10), ft.rangeQuery(1, 10.1, true, false, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, true, true, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null), ft.rangeQuery(1.1, 10, false, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, true, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null), ft.rangeQuery(1, 10.1, true, false, null));
}
public void testRangeQuery() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.LONG);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(LongPoint.newRangeQuery("field", 1, 3), ft.rangeQuery("1", "3", true, true, null));
Query expected = new IndexOrDocValuesQuery(
LongPoint.newRangeQuery("field", 1, 3),
SortedNumericDocValuesField.newRangeQuery("field", 1, 3));
assertEquals(expected, ft.rangeQuery("1", "3", true, true, null));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
@ -262,8 +270,8 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
float u = (randomFloat() * 2 - 1) * 70000;
boolean includeLower = randomBoolean();
boolean includeUpper = randomBoolean();
Query floatQ = NumberFieldMapper.NumberType.FLOAT.rangeQuery("float", l, u, includeLower, includeUpper);
Query halfFloatQ = NumberFieldMapper.NumberType.HALF_FLOAT.rangeQuery("half_float", l, u, includeLower, includeUpper);
Query floatQ = NumberFieldMapper.NumberType.FLOAT.rangeQuery("float", l, u, includeLower, includeUpper, false);
Query halfFloatQ = NumberFieldMapper.NumberType.HALF_FLOAT.rangeQuery("half_float", l, u, includeLower, includeUpper, false);
assertEquals(searcher.count(floatQ), searcher.count(halfFloatQ));
}
IOUtils.close(reader, dir);
@ -271,17 +279,73 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
public void testNegativeZero() {
assertEquals(
NumberType.DOUBLE.rangeQuery("field", null, -0d, true, true),
NumberType.DOUBLE.rangeQuery("field", null, +0d, true, false));
NumberType.DOUBLE.rangeQuery("field", null, -0d, true, true, false),
NumberType.DOUBLE.rangeQuery("field", null, +0d, true, false, false));
assertEquals(
NumberType.FLOAT.rangeQuery("field", null, -0f, true, true),
NumberType.FLOAT.rangeQuery("field", null, +0f, true, false));
NumberType.FLOAT.rangeQuery("field", null, -0f, true, true, false),
NumberType.FLOAT.rangeQuery("field", null, +0f, true, false, false));
assertEquals(
NumberType.HALF_FLOAT.rangeQuery("field", null, -0f, true, true),
NumberType.HALF_FLOAT.rangeQuery("field", null, +0f, true, false));
NumberType.HALF_FLOAT.rangeQuery("field", null, -0f, true, true, false),
NumberType.HALF_FLOAT.rangeQuery("field", null, +0f, true, false, false));
assertFalse(NumberType.DOUBLE.termQuery("field", -0d).equals(NumberType.DOUBLE.termQuery("field", +0d)));
assertFalse(NumberType.FLOAT.termQuery("field", -0f).equals(NumberType.FLOAT.termQuery("field", +0f)));
assertFalse(NumberType.HALF_FLOAT.termQuery("field", -0f).equals(NumberType.HALF_FLOAT.termQuery("field", +0f)));
}
// Make sure we construct the IndexOrDocValuesQuery objects with queries that match
// the same ranges
public void testDocValueByteRange() throws Exception {
doTestDocValueRangeQueries(NumberType.BYTE, () -> (byte) random().nextInt(256));
}
public void testDocValueShortRange() throws Exception {
doTestDocValueRangeQueries(NumberType.SHORT, () -> (short) random().nextInt(65536));
}
public void testDocValueIntRange() throws Exception {
doTestDocValueRangeQueries(NumberType.INTEGER, random()::nextInt);
}
public void testDocValueLongRange() throws Exception {
doTestDocValueRangeQueries(NumberType.LONG, random()::nextLong);
}
public void testDocValueHalfFloatRange() throws Exception {
doTestDocValueRangeQueries(NumberType.HALF_FLOAT, random()::nextFloat);
}
public void testDocValueFloatRange() throws Exception {
doTestDocValueRangeQueries(NumberType.FLOAT, random()::nextFloat);
}
public void testDocValueDoubleRange() throws Exception {
doTestDocValueRangeQueries(NumberType.DOUBLE, random()::nextDouble);
}
public void doTestDocValueRangeQueries(NumberType type, Supplier<Number> valueSupplier) throws Exception {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
final int numDocs = TestUtil.nextInt(random(), 100, 500);
for (int i = 0; i < numDocs; ++i) {
w.addDocument(type.createFields("foo", valueSupplier.get(), true, true, false));
}
DirectoryReader reader = DirectoryReader.open(w);
IndexSearcher searcher = newSearcher(reader);
w.close();
final int iters = 10;
for (int iter = 0; iter < iters; ++iter) {
Query query = type.rangeQuery("foo",
random().nextBoolean() ? null : valueSupplier.get(),
random().nextBoolean() ? null : valueSupplier.get(),
randomBoolean(), randomBoolean(), true);
assertThat(query, Matchers.instanceOf(IndexOrDocValuesQuery.class));
IndexOrDocValuesQuery indexOrDvQuery = (IndexOrDocValuesQuery) query;
assertEquals(
searcher.count(indexOrDvQuery.getIndexQuery()),
searcher.count(indexOrDvQuery.getRandomAccessQuery()));
}
reader.close();
dir.close();
}
}

View File

@ -118,7 +118,7 @@ public class ScaledFloatFieldTypeTests extends FieldTypeTestCase {
Double u = randomBoolean() ? null : (randomDouble() * 2 - 1) * 10000;
boolean includeLower = randomBoolean();
boolean includeUpper = randomBoolean();
Query doubleQ = NumberFieldMapper.NumberType.DOUBLE.rangeQuery("double", l, u, includeLower, includeUpper);
Query doubleQ = NumberFieldMapper.NumberType.DOUBLE.rangeQuery("double", l, u, includeLower, includeUpper, false);
Query scaledFloatQ = ft.rangeQuery(l, u, includeLower, includeUpper, null);
assertEquals(searcher.count(doubleQ), searcher.count(scaledFloatQ));
}

View File

@ -19,6 +19,9 @@
package org.elasticsearch.index.query;
import org.apache.lucene.document.LatLonDocValuesField;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.geo.GeoPoint;
@ -226,6 +229,19 @@ public class GeoBoundingBoxQueryBuilderTests extends AbstractQueryTestCase<GeoBo
MappedFieldType fieldType = context.fieldMapper(queryBuilder.fieldName());
if (fieldType == null) {
assertTrue("Found no indexed geo query.", query instanceof MatchNoDocsQuery);
} else if (query instanceof IndexOrDocValuesQuery) { // TODO: remove the if statement once we always use LatLonPoint
Query indexQuery = ((IndexOrDocValuesQuery) query).getIndexQuery();
assertEquals(LatLonPoint.newBoxQuery(queryBuilder.fieldName(),
queryBuilder.bottomRight().lat(),
queryBuilder.topLeft().lat(),
queryBuilder.topLeft().lon(),
queryBuilder.bottomRight().lon()), indexQuery);
Query dvQuery = ((IndexOrDocValuesQuery) query).getRandomAccessQuery();
assertEquals(LatLonDocValuesField.newBoxQuery(queryBuilder.fieldName(),
queryBuilder.bottomRight().lat(),
queryBuilder.topLeft().lat(),
queryBuilder.topLeft().lon(),
queryBuilder.bottomRight().lon()), dvQuery);
}
}

View File

@ -19,6 +19,9 @@
package org.elasticsearch.index.query;
import org.apache.lucene.document.LatLonDocValuesField;
import org.apache.lucene.document.LatLonPoint;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.ParsingException;
@ -124,7 +127,21 @@ public class GeoDistanceQueryBuilderTests extends AbstractQueryTestCase<GeoDista
@Override
protected void doAssertLuceneQuery(GeoDistanceQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
// TODO: what can we check
// TODO: remove the if statement once we always use LatLonPoint
if (query instanceof IndexOrDocValuesQuery) {
Query indexQuery = ((IndexOrDocValuesQuery) query).getIndexQuery();
assertEquals(LatLonPoint.newDistanceQuery(queryBuilder.fieldName(),
queryBuilder.point().lat(),
queryBuilder.point().lon(),
queryBuilder.distance()),
indexQuery);
Query dvQuery = ((IndexOrDocValuesQuery) query).getRandomAccessQuery();
assertEquals(LatLonDocValuesField.newDistanceQuery(queryBuilder.fieldName(),
queryBuilder.point().lat(),
queryBuilder.point().lon(),
queryBuilder.distance()),
dvQuery);
}
}
public void testParsingAndToQuery1() throws IOException {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.query;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.PointRangeQuery;
import org.apache.lucene.search.Query;
@ -94,7 +95,8 @@ public class MatchPhrasePrefixQueryBuilderTests extends AbstractQueryTestCase<Ma
assertThat(query, notNullValue());
assertThat(query,
either(instanceOf(BooleanQuery.class)).or(instanceOf(MultiPhrasePrefixQuery.class))
.or(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
.or(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class))
.or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
}
public void testIllegalValues() {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.query;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.PointRangeQuery;
@ -88,7 +89,8 @@ public class MatchPhraseQueryBuilderTests extends AbstractQueryTestCase<MatchPhr
protected void doAssertLuceneQuery(MatchPhraseQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
assertThat(query, notNullValue());
assertThat(query, either(instanceOf(BooleanQuery.class)).or(instanceOf(PhraseQuery.class))
.or(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
.or(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class))
.or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
}
public void testIllegalValues() {

View File

@ -24,6 +24,7 @@ import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.PhraseQuery;
@ -152,17 +153,17 @@ public class MatchQueryBuilderTests extends AbstractQueryTestCase<MatchQueryBuil
case BOOLEAN:
assertThat(query, either(instanceOf(BooleanQuery.class)).or(instanceOf(ExtendedCommonTermsQuery.class))
.or(instanceOf(TermQuery.class)).or(instanceOf(FuzzyQuery.class)).or(instanceOf(MatchNoDocsQuery.class))
.or(instanceOf(PointRangeQuery.class)));
.or(instanceOf(PointRangeQuery.class)).or(instanceOf(IndexOrDocValuesQuery.class)));
break;
case PHRASE:
assertThat(query, either(instanceOf(BooleanQuery.class)).or(instanceOf(PhraseQuery.class))
.or(instanceOf(TermQuery.class)).or(instanceOf(FuzzyQuery.class))
.or(instanceOf(PointRangeQuery.class)));
.or(instanceOf(PointRangeQuery.class)).or(instanceOf(IndexOrDocValuesQuery.class)));
break;
case PHRASE_PREFIX:
assertThat(query, either(instanceOf(BooleanQuery.class)).or(instanceOf(MultiPhrasePrefixQuery.class))
.or(instanceOf(TermQuery.class)).or(instanceOf(FuzzyQuery.class))
.or(instanceOf(PointRangeQuery.class)));
.or(instanceOf(PointRangeQuery.class)).or(instanceOf(IndexOrDocValuesQuery.class)));
break;
}
QueryShardContext context = searchContext.getQueryShardContext();

View File

@ -25,6 +25,7 @@ import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DisjunctionMaxQuery;
import org.apache.lucene.search.FuzzyQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.LegacyNumericRangeQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
@ -151,7 +152,7 @@ public class MultiMatchQueryBuilderTests extends AbstractQueryTestCase<MultiMatc
.or(instanceOf(MatchAllDocsQuery.class)).or(instanceOf(ExtendedCommonTermsQuery.class))
.or(instanceOf(MatchNoDocsQuery.class)).or(instanceOf(PhraseQuery.class))
.or(instanceOf(LegacyNumericRangeQuery.class))
.or(instanceOf(PointRangeQuery.class)));
.or(instanceOf(PointRangeQuery.class)).or(instanceOf(IndexOrDocValuesQuery.class)));
}
public void testIllegaArguments() {

View File

@ -23,6 +23,7 @@ import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.PointRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermRangeQuery;
@ -134,6 +135,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
assertThat(termRangeQuery.includesLower(), equalTo(queryBuilder.includeLower()));
assertThat(termRangeQuery.includesUpper(), equalTo(queryBuilder.includeUpper()));
} else if (queryBuilder.fieldName().equals(DATE_FIELD_NAME)) {
assertThat(query, instanceOf(IndexOrDocValuesQuery.class));
query = ((IndexOrDocValuesQuery) query).getIndexQuery();
assertThat(query, instanceOf(PointRangeQuery.class));
MapperService mapperService = context.getQueryShardContext().getMapperService();
MappedFieldType mappedFieldType = mapperService.fullName(DATE_FIELD_NAME);
@ -177,6 +180,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
}
assertEquals(LongPoint.newRangeQuery(DATE_FIELD_NAME, minLong, maxLong), query);
} else if (queryBuilder.fieldName().equals(INT_FIELD_NAME)) {
assertThat(query, instanceOf(IndexOrDocValuesQuery.class));
query = ((IndexOrDocValuesQuery) query).getIndexQuery();
assertThat(query, instanceOf(PointRangeQuery.class));
Integer min = (Integer) queryBuilder.from();
Integer max = (Integer) queryBuilder.to();
@ -240,6 +245,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
assumeTrue("test runs only when at least a type is registered", getCurrentTypes().length > 0);
Query parsedQuery = rangeQuery(INT_FIELD_NAME).from(23).to(54).includeLower(true).includeUpper(false).toQuery(createShardContext());
// since age is automatically registered in data, we encode it as numeric
assertThat(parsedQuery, instanceOf(IndexOrDocValuesQuery.class));
parsedQuery = ((IndexOrDocValuesQuery) parsedQuery).getIndexQuery();
assertThat(parsedQuery, instanceOf(PointRangeQuery.class));
assertEquals(IntPoint.newRangeQuery(INT_FIELD_NAME, 23, 53), parsedQuery);
}
@ -257,6 +264,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
" }\n" +
"}";
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
assertThat(parsedQuery, instanceOf(IndexOrDocValuesQuery.class));
parsedQuery = ((IndexOrDocValuesQuery) parsedQuery).getIndexQuery();
assertThat(parsedQuery, instanceOf(PointRangeQuery.class));
assertEquals(LongPoint.newRangeQuery(DATE_FIELD_NAME,
@ -288,6 +297,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
" }\n" +
"}\n";
Query parsedQuery = parseQuery(query).toQuery(createShardContext());
assertThat(parsedQuery, instanceOf(IndexOrDocValuesQuery.class));
parsedQuery = ((IndexOrDocValuesQuery) parsedQuery).getIndexQuery();
assertThat(parsedQuery, instanceOf(PointRangeQuery.class));
assertEquals(LongPoint.newRangeQuery(DATE_FIELD_NAME,
DateTime.parse("2014-11-01T00:00:00.000+00").getMillis(),
@ -303,6 +314,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
" }\n" +
"}";
parsedQuery = parseQuery(query).toQuery(createShardContext());
assertThat(parsedQuery, instanceOf(IndexOrDocValuesQuery.class));
parsedQuery = ((IndexOrDocValuesQuery) parsedQuery).getIndexQuery();
assertThat(parsedQuery, instanceOf(PointRangeQuery.class));
assertEquals(LongPoint.newRangeQuery(DATE_FIELD_NAME,
DateTime.parse("2014-11-30T23:59:59.999+00").getMillis() + 1,
@ -323,6 +336,8 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
"}";
QueryShardContext context = createShardContext();
Query parsedQuery = parseQuery(query).toQuery(context);
assertThat(parsedQuery, instanceOf(IndexOrDocValuesQuery.class));
parsedQuery = ((IndexOrDocValuesQuery) parsedQuery).getIndexQuery();
assertThat(parsedQuery, instanceOf(PointRangeQuery.class));
// TODO what else can we assert