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:
parent
61e2cf89b5
commit
1ad83c37c4
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"));
|
||||
|
|
Loading…
Reference in New Issue