Use index sort range query when possible. (#56710)

This PR proposes to use `IndexSortSortedNumericDocValuesRangeQuery` when
possible to speed up certain range queries. Points-based queries are already
very efficient, the only time this query makes a difference is when the range
matches a large number of documents.

Relates to #48665.
This commit is contained in:
Julie Tibshirani 2020-05-13 13:24:45 -07:00 committed by GitHub
parent 61e2cf89b5
commit 1ad83c37c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 317 additions and 148 deletions

View File

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

View File

@ -117,8 +117,8 @@ 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, false);
Query scaledFloatQ = ft.rangeQuery(l, u, includeLower, includeUpper, null);
Query doubleQ = NumberFieldMapper.NumberType.DOUBLE.rangeQuery("double", l, u, includeLower, includeUpper, false, MOCK_QSC);
Query scaledFloatQ = ft.rangeQuery(l, u, includeLower, includeUpper, MOCK_QSC);
assertEquals(searcher.count(doubleQ), searcher.count(scaledFloatQ));
}
IOUtils.close(reader, dir);
@ -128,19 +128,19 @@ public class ScaledFloatFieldTypeTests extends FieldTypeTestCase {
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType();
ft.setName("scaled_float");
ft.setScalingFactor(100.0);
Query scaledFloatQ = ft.rangeQuery(null, 0.1, true, false, null);
Query scaledFloatQ = ft.rangeQuery(null, 0.1, true, false, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 9]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.1, true, true, null);
scaledFloatQ = ft.rangeQuery(null, 0.1, true, true, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 10]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.095, true, false, null);
scaledFloatQ = ft.rangeQuery(null, 0.095, true, false, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 9]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.095, true, true, null);
scaledFloatQ = ft.rangeQuery(null, 0.095, true, true, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 9]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.105, true, false, null);
scaledFloatQ = ft.rangeQuery(null, 0.105, true, false, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 10]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 0.105, true, true, null);
scaledFloatQ = ft.rangeQuery(null, 0.105, true, true, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 10]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(null, 79.99, true, true, null);
scaledFloatQ = ft.rangeQuery(null, 79.99, true, true, MOCK_QSC);
assertEquals("scaled_float:[-9223372036854775808 TO 7999]", scaledFloatQ.toString());
}
@ -148,17 +148,17 @@ public class ScaledFloatFieldTypeTests extends FieldTypeTestCase {
ScaledFloatFieldMapper.ScaledFloatFieldType ft = new ScaledFloatFieldMapper.ScaledFloatFieldType();
ft.setName("scaled_float");
ft.setScalingFactor(100.0);
Query scaledFloatQ = ft.rangeQuery(-0.1, null, false, true, null);
Query scaledFloatQ = ft.rangeQuery(-0.1, null, false, true, MOCK_QSC);
assertEquals("scaled_float:[-9 TO 9223372036854775807]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(-0.1, null, true, true, null);
scaledFloatQ = ft.rangeQuery(-0.1, null, true, true, MOCK_QSC);
assertEquals("scaled_float:[-10 TO 9223372036854775807]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(-0.095, null, false, true, null);
scaledFloatQ = ft.rangeQuery(-0.095, null, false, true, MOCK_QSC);
assertEquals("scaled_float:[-9 TO 9223372036854775807]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(-0.095, null, true, true, null);
scaledFloatQ = ft.rangeQuery(-0.095, null, true, true, MOCK_QSC);
assertEquals("scaled_float:[-9 TO 9223372036854775807]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(-0.105, null, false, true, null);
scaledFloatQ = ft.rangeQuery(-0.105, null, false, true, MOCK_QSC);
assertEquals("scaled_float:[-10 TO 9223372036854775807]", scaledFloatQ.toString());
scaledFloatQ = ft.rangeQuery(-0.105, null, true, true, null);
scaledFloatQ = ft.rangeQuery(-0.105, null, true, true, MOCK_QSC);
assertEquals("scaled_float:[-10 TO 9223372036854775807]", scaledFloatQ.toString());
}

View File

@ -95,6 +95,7 @@ import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
import org.junit.After;
@ -123,6 +124,7 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
private IndexWriter indexWriter;
private DocumentMapper documentMapper;
private DirectoryReader directoryReader;
private IndexService indexService;
private MapperService mapperService;
private PercolatorFieldMapper fieldMapper;
@ -144,7 +146,7 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
indexWriter = new IndexWriter(directory, config);
String indexName = "test";
IndexService indexService = createIndex(indexName, Settings.EMPTY);
indexService = createIndex(indexName, Settings.EMPTY);
mapperService = indexService.mapperService();
String mapper = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
@ -197,6 +199,7 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
}
Collections.sort(intValues);
QueryShardContext context = createSearchContext(indexService).getQueryShardContext();
MappedFieldType intFieldType = mapperService.fieldType("int_field");
List<Supplier<Query>> queryFunctions = new ArrayList<>();
@ -207,10 +210,10 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
queryFunctions.add(() -> new TermQuery(new Term(field1, randomFrom(stringContent.get(field1)))));
String field2 = randomFrom(stringFields);
queryFunctions.add(() -> new TermQuery(new Term(field2, randomFrom(stringContent.get(field2)))));
queryFunctions.add(() -> intFieldType.termQuery(randomFrom(intValues), null));
queryFunctions.add(() -> intFieldType.termsQuery(Arrays.asList(randomFrom(intValues), randomFrom(intValues)), null));
queryFunctions.add(() -> intFieldType.termQuery(randomFrom(intValues), context));
queryFunctions.add(() -> intFieldType.termsQuery(Arrays.asList(randomFrom(intValues), randomFrom(intValues)), context));
queryFunctions.add(() -> intFieldType.rangeQuery(intValues.get(4), intValues.get(intValues.size() - 4), true,
true, ShapeRelation.WITHIN, null, null, null));
true, ShapeRelation.WITHIN, null, null, context));
queryFunctions.add(() -> new TermInSetQuery(field1, new BytesRef(randomFrom(stringContent.get(field1))),
new BytesRef(randomFrom(stringContent.get(field1)))));
queryFunctions.add(() -> new TermInSetQuery(field2, new BytesRef(randomFrom(stringContent.get(field1))),
@ -335,6 +338,7 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
ranges.add(new int[]{0, 10});
ranges.add(new int[]{15, 50});
QueryShardContext context = createSearchContext(indexService).getQueryShardContext();
List<ParseContext.Document> documents = new ArrayList<>();
{
addQuery(new TermQuery(new Term("string_field", randomFrom(stringValues))), documents);
@ -344,13 +348,13 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
}
{
int[] range = randomFrom(ranges);
Query rangeQuery = intFieldType.rangeQuery(range[0], range[1], true, true, null, null, null, null);
Query rangeQuery = intFieldType.rangeQuery(range[0], range[1], true, true, null, null, null, context);
addQuery(rangeQuery, documents);
}
{
int numBooleanQueries = randomIntBetween(1, 5);
for (int i = 0; i < numBooleanQueries; i++) {
Query randomBQ = randomBQ(1, stringValues, ranges, intFieldType);
Query randomBQ = randomBQ(1, stringValues, ranges, intFieldType, context);
addQuery(randomBQ, documents);
}
}
@ -375,6 +379,7 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
MemoryIndex memoryIndex = MemoryIndex.fromDocument(document, new WhitespaceAnalyzer());
duelRun(queryStore, memoryIndex, shardSearcher);
}
for (int[] range : ranges) {
List<Field> numberFields =
NumberFieldMapper.NumberType.INTEGER.createFields("int_field", between(range[0], range[1]), true, true, false);
@ -387,7 +392,8 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
}
}
private BooleanQuery randomBQ(int depth, List<String> stringValues, List<int[]> ranges, MappedFieldType intFieldType) {
private BooleanQuery randomBQ(int depth, List<String> stringValues, List<int[]> ranges,
MappedFieldType intFieldType, QueryShardContext context) {
final int numClauses = randomIntBetween(1, 4);
final boolean onlyShouldClauses = randomBoolean();
final BooleanQuery.Builder builder = new BooleanQuery.Builder();
@ -396,10 +402,10 @@ public class CandidateQueryTests extends ESSingleNodeTestCase {
for (int i = 0; i < numClauses; i++) {
Query subQuery;
if (randomBoolean() && depth <= 3) {
subQuery = randomBQ(depth + 1, stringValues, ranges, intFieldType);
subQuery = randomBQ(depth + 1, stringValues, ranges, intFieldType, context);
} else if (randomBoolean()) {
int[] range = randomFrom(ranges);
subQuery = intFieldType.rangeQuery(range[0], range[1], true, true, null, null, null, null);
subQuery = intFieldType.rangeQuery(range[0], range[1], true, true, null, null, null, context);
} else {
subQuery = new TermQuery(new Term("string_field", randomFrom(stringValues)));
}

View File

@ -227,13 +227,14 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase {
}
public void testExtractRanges() throws Exception {
QueryShardContext context = createSearchContext(indexService).getQueryShardContext();
addQueryFieldMappings();
BooleanQuery.Builder bq = new BooleanQuery.Builder();
Query rangeQuery1 = mapperService.fieldType("number_field1")
.rangeQuery(10, 20, true, true, null, null, null, null);
.rangeQuery(10, 20, true, true, null, null, null, context);
bq.add(rangeQuery1, Occur.MUST);
Query rangeQuery2 = mapperService.fieldType("number_field1")
.rangeQuery(15, 20, true, true, null, null, null, null);
.rangeQuery(15, 20, true, true, null, null, null, context);
bq.add(rangeQuery2, Occur.MUST);
DocumentMapper documentMapper = mapperService.documentMapper("doc");
@ -265,7 +266,7 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase {
bq = new BooleanQuery.Builder();
bq.add(rangeQuery1, Occur.MUST);
rangeQuery2 = mapperService.fieldType("number_field2")
.rangeQuery(15, 20, true, true, null, null, null, null);
.rangeQuery(15, 20, true, true, null, null, null, context);
bq.add(rangeQuery2, Occur.MUST);
parseContext = new ParseContext.InternalParseContext(settings,

View File

@ -171,6 +171,11 @@ public final class IndexSortConfig {
return sortSpecs.length > 0;
}
public boolean hasPrimarySortOnField(String field) {
return sortSpecs.length > 0
&& sortSpecs[0].field.equals(field);
}
/**
* Builds the {@link Sort} order from the settings for this index
* or returns null if this index has no sort.

View File

@ -29,6 +29,7 @@ import org.apache.lucene.index.Term;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.BytesRef;
@ -437,11 +438,17 @@ public final class DateFieldMapper extends FieldMapper {
--u;
}
}
Query query = LongPoint.newRangeQuery(name(), l, u);
if (hasDocValues()) {
Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery(name(), l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
if (context.indexSortedOnField(name())) {
query = new IndexSortSortedNumericDocValuesRangeQuery(name(), l, u, query);
}
}
if (nowUsed[0]) {
query = new DateRangeIncludingNowQuery(query);
}

View File

@ -34,6 +34,7 @@ import org.apache.lucene.index.Term;
import org.apache.lucene.search.BoostQuery;
import org.apache.lucene.search.DocValuesFieldExistsQuery;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
@ -218,8 +219,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
float l = Float.NEGATIVE_INFINITY;
float u = Float.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -315,8 +316,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
float l = Float.NEGATIVE_INFINITY;
float u = Float.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -334,8 +335,8 @@ public class NumberFieldMapper extends FieldMapper {
Query query = FloatPoint.newRangeQuery(field, l, u);
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery(field,
NumericUtils.floatToSortableInt(l),
NumericUtils.floatToSortableInt(u));
NumericUtils.floatToSortableInt(l),
NumericUtils.floatToSortableInt(u));
query = new IndexOrDocValuesQuery(query, dvQuery);
}
return query;
@ -401,8 +402,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
double l = Double.NEGATIVE_INFINITY;
double u = Double.POSITIVE_INFINITY;
if (lowerTerm != null) {
@ -495,9 +496,9 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues);
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues, context);
}
@Override
@ -552,9 +553,9 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues);
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
return INTEGER.rangeQuery(field, lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues, context);
}
@Override
@ -629,8 +630,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
int l = Integer.MIN_VALUE;
int u = Integer.MAX_VALUE;
if (lowerTerm != null) {
@ -664,6 +665,9 @@ public class NumberFieldMapper extends FieldMapper {
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery(field, l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
if (context.indexSortedOnField(field)) {
query = new IndexSortSortedNumericDocValuesRangeQuery(field, l, u, query);
}
}
return query;
}
@ -748,8 +752,8 @@ public class NumberFieldMapper extends FieldMapper {
@Override
public Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues) {
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context) {
long l = Long.MIN_VALUE;
long u = Long.MAX_VALUE;
if (lowerTerm != null) {
@ -783,6 +787,9 @@ public class NumberFieldMapper extends FieldMapper {
if (hasDocValues) {
Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery(field, l, u);
query = new IndexOrDocValuesQuery(query, dvQuery);
if (context.indexSortedOnField(field)) {
query = new IndexSortSortedNumericDocValuesRangeQuery(field, l, u, query);
}
}
return query;
}
@ -823,8 +830,8 @@ public class NumberFieldMapper extends FieldMapper {
public abstract Query termQuery(String field, Object value);
public abstract Query termsQuery(String field, List<Object> values);
public abstract Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
boolean includeLower, boolean includeUpper,
boolean hasDocValues);
boolean includeLower, boolean includeUpper,
boolean hasDocValues, QueryShardContext context);
public abstract Number parse(XContentParser parser, boolean coerce) throws IOException;
public abstract Number parse(Object value, boolean coerce);
public abstract Number parsePoint(byte[] value);
@ -946,7 +953,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, hasDocValues());
Query query = type.rangeQuery(name(), lowerTerm, upperTerm, includeLower, includeUpper, hasDocValues(), context);
if (boost() != 1f) {
query = new BoostQuery(query, boost());
}

View File

@ -41,6 +41,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.IndexSortConfig;
import org.elasticsearch.index.analysis.IndexAnalyzers;
import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
import org.elasticsearch.index.fielddata.IndexFieldData;
@ -348,6 +349,11 @@ public class QueryShardContext extends QueryRewriteContext {
return indexNameMatcher.test(pattern);
}
public boolean indexSortedOnField(String field) {
IndexSortConfig indexSortConfig = indexSettings.getIndexSortConfig();
return indexSortConfig.hasPrimarySortOnField(field);
}
public ParsedQuery toQuery(QueryBuilder queryBuilder) {
return toQuery(queryBuilder, q -> {
Query query = q.toQuery(this);

View File

@ -30,6 +30,7 @@ import org.apache.lucene.index.MultiReader;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.elasticsearch.Version;
@ -41,9 +42,9 @@ import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.fielddata.plain.SortedNumericDVIndexFieldData;
import org.elasticsearch.index.fielddata.LeafNumericFieldData;
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
import org.elasticsearch.index.mapper.DateFieldMapper.Resolution;
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
@ -285,6 +286,38 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
public void testRangeQueryWithIndexSort() {
Settings settings = Settings.builder()
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
.put("index.sort.field", "field")
.build();
IndexMetadata indexMetadata = new IndexMetadata.Builder("index")
.settings(settings)
.build();
IndexSettings indexSettings = new IndexSettings(indexMetadata, settings);
QueryShardContext context = new QueryShardContext(0, indexSettings,
BigArrays.NON_RECYCLING_INSTANCE, null, null, null, null, null, xContentRegistry(), writableRegistry(),
null, null, () -> 0L, null, null, () -> true, null);
MappedFieldType ft = createDefaultFieldType();
ft.setName("field");
String date1 = "2015-10-12T14:10:55";
String date2 = "2016-04-28T11:33:52";
long instant1 = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date1)).toInstant().toEpochMilli();
long instant2 = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date2)).toInstant().toEpochMilli() + 999;
ft.setIndexOptions(IndexOptions.DOCS);
Query pointQuery = LongPoint.newRangeQuery("field", instant1, instant2);
Query dvQuery = SortedNumericDocValuesField.newSlowRangeQuery("field", instant1, instant2);
Query expected = new IndexSortSortedNumericDocValuesRangeQuery("field", instant1, instant2,
new IndexOrDocValuesQuery(pointQuery, dvQuery));
assertEquals(expected, ft.rangeQuery(date1, date2, true, true, null, null, null, context));
}
public void testDateNanoDocValues() throws IOException {
// Create an index with some docValues
Directory dir = newDirectory();

View File

@ -33,16 +33,26 @@ 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.IndexSortSortedNumericDocValuesRangeQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.TestUtil;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.MappedFieldType.Relation;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberFieldType;
import org.hamcrest.Matchers;
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.MultiValueMode;
import org.junit.Before;
import java.io.IOException;
@ -55,6 +65,7 @@ import java.util.function.Supplier;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
public class NumberFieldTypeTests extends FieldTypeTestCase {
@ -150,116 +161,116 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
MappedFieldType ftInt = new NumberFieldMapper.NumberFieldType(NumberType.INTEGER);
ftInt.setName("field");
ftInt.setIndexOptions(IndexOptions.DOCS);
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null, null, null, null),
ftInt.rangeQuery(-3.5, -2.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null, null, null, null),
ftInt.rangeQuery(-3.5, -2.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null, null, null, null),
ftInt.rangeQuery(-0.5, 0.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null, null, null, null),
ftInt.rangeQuery(-0.5, 0.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null, null, null, null),
ftInt.rangeQuery(0.5, 2.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null, null, null, null),
ftInt.rangeQuery(0.5, 2.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null, null, null, null),
ftInt.rangeQuery(-0.5, 2.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null, null, null, null),
ftInt.rangeQuery(-0.5, 2.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-3.5, -2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(-3, -3, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-3.5, -2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-0.5, 0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(0, 0, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-0.5, 0.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(0.5, 2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(1, 2, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(0.5, 2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-0.5, 2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(0, 2, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-0.5, 2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null, null, null, null),
ftInt.rangeQuery(-2.5, 0.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null, null, null, null),
ftInt.rangeQuery(-2.5, 0.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null, null, null, null),
ftInt.rangeQuery(-2.5, -0.5, true, true, null, null, null, null));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null, null, null, null),
ftInt.rangeQuery(-2.5, -0.5, false, false, null, null, null, null));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-2.5, 0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(-2, 0, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-2.5, 0.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-2.5, -0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftInt.rangeQuery(-2, -1, true, true, null, null, null, MOCK_QSC),
ftInt.rangeQuery(-2.5, -0.5, false, false, null, null, null, MOCK_QSC));
MappedFieldType ftLong = new NumberFieldMapper.NumberFieldType(NumberType.LONG);
ftLong.setName("field");
ftLong.setIndexOptions(IndexOptions.DOCS);
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null, null, null, null),
ftLong.rangeQuery(-3.5, -2.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null, null, null, null),
ftLong.rangeQuery(-3.5, -2.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null, null, null, null),
ftLong.rangeQuery(-0.5, 0.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null, null, null, null),
ftLong.rangeQuery(-0.5, 0.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null, null, null, null),
ftLong.rangeQuery(0.5, 2.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null, null, null, null),
ftLong.rangeQuery(0.5, 2.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null, null, null, null),
ftLong.rangeQuery(-0.5, 2.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null, null, null, null),
ftLong.rangeQuery(-0.5, 2.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-3.5, -2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(-3, -3, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-3.5, -2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-0.5, 0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(0, 0, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-0.5, 0.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(0.5, 2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(1, 2, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(0.5, 2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-0.5, 2.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(0, 2, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-0.5, 2.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null, null, null, null),
ftLong.rangeQuery(-2.5, 0.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null, null, null, null),
ftLong.rangeQuery(-2.5, 0.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null, null, null, null),
ftLong.rangeQuery(-2.5, -0.5, true, true, null, null, null, null));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null, null, null, null),
ftLong.rangeQuery(-2.5, -0.5, false, false, null, null, null, null));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-2.5, 0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(-2, 0, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-2.5, 0.5, false, false, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-2.5, -0.5, true, true, null, null, null, MOCK_QSC));
assertEquals(ftLong.rangeQuery(-2, -1, true, true, null, null, null, MOCK_QSC),
ftLong.rangeQuery(-2.5, -0.5, false, false, null, null, null, MOCK_QSC));
}
public void testByteRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.BYTE);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, false, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, false, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, false, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, false, null, null, null, MOCK_QSC));
}
public void testShortRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.SHORT);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, false, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, false, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, false, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, false, null, null, null, MOCK_QSC));
}
public void testIntegerRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.INTEGER);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, false, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, false, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, false, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, false, null, null, null, MOCK_QSC));
}
public void testLongRangeQueryWithDecimalParts() {
MappedFieldType ft = new NumberFieldMapper.NumberFieldType(NumberType.LONG);
ft.setName("field");
ft.setIndexOptions(IndexOptions.DOCS);
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, null),
ft.rangeQuery(1.1, 10, false, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, true, null, null, null, null));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, null),
ft.rangeQuery(1, 10.1, true, false, null, null, null, null));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(2, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1.1, 10, false, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, true, null, null, null, MOCK_QSC));
assertEquals(ft.rangeQuery(1, 10, true, true, null, null, null, MOCK_QSC),
ft.rangeQuery(1, 10.1, true, false, null, null, null, MOCK_QSC));
}
public void testRangeQuery() {
@ -269,11 +280,11 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
Query expected = new IndexOrDocValuesQuery(
LongPoint.newRangeQuery("field", 1, 3),
SortedNumericDocValuesField.newSlowRangeQuery("field", 1, 3));
assertEquals(expected, ft.rangeQuery("1", "3", true, true, null, null, null, null));
assertEquals(expected, ft.rangeQuery("1", "3", true, true, null, null, null, MOCK_QSC));
ft.setIndexOptions(IndexOptions.NONE);
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> ft.rangeQuery("1", "3", true, true, null, null, null, null));
() -> ft.rangeQuery("1", "3", true, true, null, null, null, MOCK_QSC));
assertEquals("Cannot search on field [field] since it is not indexed.", e.getMessage());
}
@ -357,6 +368,7 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
}
final DirectoryReader reader = DirectoryReader.open(w);
w.close();
IndexSearcher searcher = newSearcher(reader);
final int numQueries = 1000;
for (int i = 0; i < numQueries; ++i) {
@ -364,8 +376,8 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
float u = (randomFloat() * 2 - 1) * 65504;
boolean includeLower = randomBoolean();
boolean includeUpper = randomBoolean();
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);
Query floatQ = NumberType.FLOAT.rangeQuery("float", l, u, includeLower, includeUpper, false, MOCK_QSC);
Query halfFloatQ = NumberType.HALF_FLOAT.rangeQuery("half_float", l, u, includeLower, includeUpper, false, MOCK_QSC);
assertEquals(searcher.count(floatQ), searcher.count(halfFloatQ));
}
IOUtils.close(reader, dir);
@ -373,14 +385,14 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
public void testNegativeZero() {
assertEquals(
NumberType.DOUBLE.rangeQuery("field", null, -0d, true, true, false),
NumberType.DOUBLE.rangeQuery("field", null, +0d, true, false, false));
NumberType.DOUBLE.rangeQuery("field", null, -0d, true, true, false, MOCK_QSC),
NumberType.DOUBLE.rangeQuery("field", null, +0d, true, false, false, MOCK_QSC));
assertEquals(
NumberType.FLOAT.rangeQuery("field", null, -0f, true, true, false),
NumberType.FLOAT.rangeQuery("field", null, +0f, true, false, false));
NumberType.FLOAT.rangeQuery("field", null, -0f, true, true, false, MOCK_QSC),
NumberType.FLOAT.rangeQuery("field", null, +0f, true, false, false, MOCK_QSC));
assertEquals(
NumberType.HALF_FLOAT.rangeQuery("field", null, -0f, true, true, false),
NumberType.HALF_FLOAT.rangeQuery("field", null, +0f, true, false, false));
NumberType.HALF_FLOAT.rangeQuery("field", null, -0f, true, true, false, MOCK_QSC),
NumberType.HALF_FLOAT.rangeQuery("field", null, +0f, true, false, false, MOCK_QSC));
assertFalse(NumberType.DOUBLE.termQuery("field", -0d).equals(NumberType.DOUBLE.termQuery("field", +0d)));
assertFalse(NumberType.FLOAT.termQuery("field", -0f).equals(NumberType.FLOAT.termQuery("field", +0f)));
@ -432,8 +444,8 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
Query query = type.rangeQuery("foo",
random().nextBoolean() ? null : valueSupplier.get(),
random().nextBoolean() ? null : valueSupplier.get(),
randomBoolean(), randomBoolean(), true);
assertThat(query, Matchers.instanceOf(IndexOrDocValuesQuery.class));
randomBoolean(), randomBoolean(), true, MOCK_QSC);
assertThat(query, instanceOf(IndexOrDocValuesQuery.class));
IndexOrDocValuesQuery indexOrDvQuery = (IndexOrDocValuesQuery) query;
assertEquals(
searcher.count(indexOrDvQuery.getIndexQuery()),
@ -443,6 +455,75 @@ public class NumberFieldTypeTests extends FieldTypeTestCase {
dir.close();
}
public void testIndexSortIntRange() throws Exception {
doTestIndexSortRangeQueries(NumberType.INTEGER, random()::nextInt);
}
public void testIndexSortLongRange() throws Exception {
doTestIndexSortRangeQueries(NumberType.LONG, random()::nextLong);
}
public void doTestIndexSortRangeQueries(NumberType type, Supplier<Number> valueSupplier) throws IOException {
// Create index settings with an index sort.
Settings settings = Settings.builder()
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
.put("index.sort.field", "field")
.build();
IndexMetadata indexMetadata = new IndexMetadata.Builder("index")
.settings(settings)
.build();
IndexSettings indexSettings = new IndexSettings(indexMetadata, settings);
// Create an index writer configured with the same index sort.
NumberFieldType fieldType = new NumberFieldType(type);
fieldType.setName("field");
IndexNumericFieldData fielddata = (IndexNumericFieldData) fieldType.fielddataBuilder("index")
.build(indexSettings, fieldType, null, null, null);
SortField sortField = fielddata.sortField(null, MultiValueMode.MIN, null, randomBoolean());
IndexWriterConfig writerConfig = new IndexWriterConfig();
writerConfig.setIndexSort(new Sort(sortField));
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, writerConfig);
final int numDocs = TestUtil.nextInt(random(), 100, 500);
for (int i = 0; i < numDocs; ++i) {
w.addDocument(type.createFields("field", valueSupplier.get(), true, true, false));
}
// Ensure that the optimized index sort query gives the same results as a points query.
DirectoryReader reader = DirectoryReader.open(w);
IndexSearcher searcher = newSearcher(reader);
QueryShardContext context = new QueryShardContext(0, indexSettings,
BigArrays.NON_RECYCLING_INSTANCE, null, null, null, null, null, xContentRegistry(), writableRegistry(),
null, null, () -> 0L, null, null, () -> true, null);
final int iters = 10;
for (int iter = 0; iter < iters; ++iter) {
Query query = type.rangeQuery("field",
random().nextBoolean() ? null : valueSupplier.get(),
random().nextBoolean() ? null : valueSupplier.get(),
randomBoolean(), randomBoolean(), true, context);
assertThat(query, instanceOf(IndexSortSortedNumericDocValuesRangeQuery.class));
Query fallbackQuery = ((IndexSortSortedNumericDocValuesRangeQuery) query).getFallbackQuery();
assertThat(fallbackQuery, instanceOf(IndexOrDocValuesQuery.class));
IndexOrDocValuesQuery indexOrDvQuery = (IndexOrDocValuesQuery) fallbackQuery;
assertEquals(
searcher.count(query),
searcher.count(indexOrDvQuery.getIndexQuery()));
}
reader.close();
w.close();
dir.close();
}
public void testParseOutOfRangeValues() throws IOException {
final List<OutOfRangeSpec<Object>> inputs = Arrays.asList(
OutOfRangeSpec.of(NumberType.BYTE, "128", "out of range for a byte"),

View File

@ -134,6 +134,28 @@ public class QueryShardContextTests extends ESTestCase {
assertThat(shardContext.getFullyQualifiedIndex().getUUID(), equalTo(indexUuid));
}
public void testIndexSortedOnField() {
Settings settings = Settings.builder()
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 1)
.put("index.sort.field", "sort_field")
.build();
IndexMetadata indexMetadata = new IndexMetadata.Builder("index")
.settings(settings)
.build();
IndexSettings indexSettings = new IndexSettings(indexMetadata, settings);
QueryShardContext context = new QueryShardContext(
0, indexSettings, BigArrays.NON_RECYCLING_INSTANCE, null, null,
null, null, null, NamedXContentRegistry.EMPTY, new NamedWriteableRegistry(Collections.emptyList()),
null, null, () -> 0L, null, null, () -> true, null);
assertTrue(context.indexSortedOnField("sort_field"));
assertFalse(context.indexSortedOnField("second_sort_field"));
assertFalse(context.indexSortedOnField("non_sort_field"));
}
public static QueryShardContext createQueryShardContext(String indexUuid, String clusterAlias) {
IndexMetadata.Builder indexMetadataBuilder = new IndexMetadata.Builder("index");
indexMetadataBuilder.settings(Settings.builder().put("index.version.created", Version.CURRENT)

View File

@ -178,28 +178,29 @@ public class NestedHelperTests extends ESSingleNodeTestCase {
}
public void testRangeQuery() {
Query rangeQuery = mapperService.fieldType("foo2").rangeQuery(2, 5, true, true, null, null, null, null);
QueryShardContext context = createSearchContext(indexService).getQueryShardContext();
Query rangeQuery = mapperService.fieldType("foo2").rangeQuery(2, 5, true, true, null, null, null, context);
assertFalse(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fieldType("nested1.foo2").rangeQuery(2, 5, true, true, null, null, null, null);
rangeQuery = mapperService.fieldType("nested1.foo2").rangeQuery(2, 5, true, true, null, null, null, context);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertFalse(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fieldType("nested2.foo2").rangeQuery(2, 5, true, true, null, null, null, null);
rangeQuery = mapperService.fieldType("nested2.foo2").rangeQuery(2, 5, true, true, null, null, null, context);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested3"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested_missing"));
rangeQuery = mapperService.fieldType("nested3.foo2").rangeQuery(2, 5, true, true, null, null, null, null);
rangeQuery = mapperService.fieldType("nested3.foo2").rangeQuery(2, 5, true, true, null, null, null, context);
assertTrue(new NestedHelper(mapperService).mightMatchNestedDocs(rangeQuery));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested1"));
assertTrue(new NestedHelper(mapperService).mightMatchNonNestedDocs(rangeQuery, "nested2"));