Generalize how queries on `_index` are handled at rewrite time (#52815)
Generalize how queries on `_index` are handled at rewrite time (#52486) Since this change refactors rewrites, I also took it as an opportunity to adrress #49254: instead of returning the same queries you would get on a keyword field when a field is unmapped, queries get rewritten to a MatchNoDocsQueryBuilder. This change exposed a couple bugs, like the fact that the percolator doesn't rewrite queries at query time, or that the significant_terms aggregation doesn't rewrite its inner filter, which I fixed. Closes #49254
This commit is contained in:
parent
ad3a3b1af9
commit
1807f86751
|
@ -24,6 +24,7 @@ import org.apache.lucene.analysis.Analyzer;
|
|||
import org.apache.lucene.analysis.DelegatingAnalyzerWrapper;
|
||||
import org.apache.lucene.index.BinaryDocValues;
|
||||
import org.apache.lucene.index.DirectoryReader;
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.index.IndexReaderContext;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.IndexWriterConfig;
|
||||
|
@ -78,6 +79,7 @@ import org.elasticsearch.index.query.QueryBuilder;
|
|||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.QueryShardException;
|
||||
import org.elasticsearch.index.query.Rewriteable;
|
||||
import org.elasticsearch.indices.breaker.CircuitBreakerService;
|
||||
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
||||
|
||||
|
@ -91,7 +93,6 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.elasticsearch.percolator.PercolatorFieldMapper.parseQuery;
|
||||
import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
|
||||
|
||||
public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBuilder> {
|
||||
|
@ -646,9 +647,9 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu
|
|||
PercolatorFieldMapper.FieldType pft = (PercolatorFieldMapper.FieldType) fieldType;
|
||||
String name = this.name != null ? this.name : pft.name();
|
||||
QueryShardContext percolateShardContext = wrap(context);
|
||||
PercolatorFieldMapper.configureContext(percolateShardContext, pft.mapUnmappedFieldsAsText);;
|
||||
PercolateQuery.QueryStore queryStore = createStore(pft.queryBuilderField,
|
||||
percolateShardContext,
|
||||
pft.mapUnmappedFieldsAsText);
|
||||
percolateShardContext);
|
||||
|
||||
return pft.percolateQuery(name, queryStore, documents, docSearcher, excludeNestedDocuments, context.indexVersionCreated());
|
||||
}
|
||||
|
@ -695,8 +696,7 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu
|
|||
}
|
||||
|
||||
static PercolateQuery.QueryStore createStore(MappedFieldType queryBuilderFieldType,
|
||||
QueryShardContext context,
|
||||
boolean mapUnmappedFieldsAsString) {
|
||||
QueryShardContext context) {
|
||||
Version indexVersion = context.indexVersionCreated();
|
||||
NamedWriteableRegistry registry = context.getWriteableRegistry();
|
||||
return ctx -> {
|
||||
|
@ -723,7 +723,8 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu
|
|||
assert valueLength > 0;
|
||||
QueryBuilder queryBuilder = input.readNamedWriteable(QueryBuilder.class);
|
||||
assert in.read() == -1;
|
||||
return PercolatorFieldMapper.toQuery(context, mapUnmappedFieldsAsString, queryBuilder);
|
||||
queryBuilder = Rewriteable.rewrite(queryBuilder, context);
|
||||
return queryBuilder.toQuery(context);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -739,7 +740,10 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu
|
|||
try (XContentParser sourceParser = xContent
|
||||
.createParser(context.getXContentRegistry(), LoggingDeprecationHandler.INSTANCE,
|
||||
qbSource.bytes, qbSource.offset, qbSource.length)) {
|
||||
return parseQuery(context, mapUnmappedFieldsAsString, sourceParser);
|
||||
QueryBuilder queryBuilder = PercolatorFieldMapper.parseQueryBuilder(sourceParser,
|
||||
sourceParser.getTokenLocation());
|
||||
queryBuilder = Rewriteable.rewrite(queryBuilder, context);
|
||||
return queryBuilder.toQuery(context);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
|
@ -755,6 +759,13 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu
|
|||
static QueryShardContext wrap(QueryShardContext shardContext) {
|
||||
return new QueryShardContext(shardContext) {
|
||||
|
||||
@Override
|
||||
public IndexReader getIndexReader() {
|
||||
// The reader that matters in this context is not the reader of the shard but
|
||||
// the reader of the MemoryIndex. We just use `null` for simplicity.
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitSetProducer bitsetFilter(Query query) {
|
||||
return context -> {
|
||||
|
|
|
@ -397,6 +397,8 @@ public class PercolatorFieldMapper extends FieldMapper {
|
|||
throw new IllegalArgumentException("a document can only contain one percolator query");
|
||||
}
|
||||
|
||||
configureContext(queryShardContext, isMapUnmappedFieldAsText());
|
||||
|
||||
XContentParser parser = context.parser();
|
||||
QueryBuilder queryBuilder = parseQueryBuilder(
|
||||
parser, parser.getTokenLocation()
|
||||
|
@ -410,7 +412,8 @@ public class PercolatorFieldMapper extends FieldMapper {
|
|||
Version indexVersion = context.mapperService().getIndexSettings().getIndexVersionCreated();
|
||||
createQueryBuilderField(indexVersion, queryBuilderField, queryBuilder, context);
|
||||
|
||||
Query query = toQuery(queryShardContext, isMapUnmappedFieldAsText(), queryBuilder);
|
||||
QueryBuilder queryBuilderForProcessing = queryBuilder.rewrite(new QueryShardContext(queryShardContext));
|
||||
Query query = queryBuilderForProcessing.toQuery(queryShardContext);
|
||||
processQuery(query, context);
|
||||
}
|
||||
|
||||
|
@ -480,11 +483,7 @@ public class PercolatorFieldMapper extends FieldMapper {
|
|||
}
|
||||
}
|
||||
|
||||
static Query parseQuery(QueryShardContext context, boolean mapUnmappedFieldsAsString, XContentParser parser) throws IOException {
|
||||
return toQuery(context, mapUnmappedFieldsAsString, parseQueryBuilder(parser, parser.getTokenLocation()));
|
||||
}
|
||||
|
||||
static Query toQuery(QueryShardContext context, boolean mapUnmappedFieldsAsString, QueryBuilder queryBuilder) throws IOException {
|
||||
static void configureContext(QueryShardContext context, boolean mapUnmappedFieldsAsString) {
|
||||
// This means that fields in the query need to exist in the mapping prior to registering this query
|
||||
// The reason that this is required, is that if a field doesn't exist then the query assumes defaults, which may be undesired.
|
||||
//
|
||||
|
@ -499,10 +498,9 @@ public class PercolatorFieldMapper extends FieldMapper {
|
|||
// as an analyzed string.
|
||||
context.setAllowUnmappedFields(false);
|
||||
context.setMapUnmappedFieldAsString(mapUnmappedFieldsAsString);
|
||||
return queryBuilder.toQuery(context);
|
||||
}
|
||||
|
||||
private static QueryBuilder parseQueryBuilder(XContentParser parser, XContentLocation location) {
|
||||
static QueryBuilder parseQueryBuilder(XContentParser parser, XContentLocation location) {
|
||||
try {
|
||||
return parseInnerQueryBuilder(parser);
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -38,10 +38,12 @@ import org.elasticsearch.index.Index;
|
|||
import org.elasticsearch.index.fielddata.plain.BytesBinaryDVIndexFieldData;
|
||||
import org.elasticsearch.index.mapper.BinaryFieldMapper;
|
||||
import org.elasticsearch.index.mapper.ContentPath;
|
||||
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
||||
import org.elasticsearch.index.mapper.Mapper;
|
||||
import org.elasticsearch.index.mapper.ParseContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||
import org.elasticsearch.mock.orig.Mockito;
|
||||
import org.elasticsearch.search.SearchModule;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
|
@ -93,7 +95,14 @@ public class QueryBuilderStoreTests extends ESTestCase {
|
|||
when(queryShardContext.getXContentRegistry()).thenReturn(xContentRegistry());
|
||||
when(queryShardContext.getForField(fieldMapper.fieldType()))
|
||||
.thenReturn(new BytesBinaryDVIndexFieldData(new Index("index", "uuid"), fieldMapper.name()));
|
||||
PercolateQuery.QueryStore queryStore = PercolateQueryBuilder.createStore(fieldMapper.fieldType(), queryShardContext, false);
|
||||
when(queryShardContext.fieldMapper(Mockito.anyString())).thenAnswer(invocation -> {
|
||||
final String fieldName = (String) invocation.getArguments()[0];
|
||||
KeywordFieldMapper.KeywordFieldType ft = new KeywordFieldMapper.KeywordFieldType();
|
||||
ft.setName(fieldName);
|
||||
ft.freeze();
|
||||
return ft;
|
||||
});
|
||||
PercolateQuery.QueryStore queryStore = PercolateQueryBuilder.createStore(fieldMapper.fieldType(), queryShardContext);
|
||||
|
||||
try (IndexReader indexReader = DirectoryReader.open(directory)) {
|
||||
LeafReaderContext leafContext = indexReader.leaves().get(0);
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.mapper;
|
||||
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.regex.Regex;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link MappedFieldType} that has the same value for all documents.
|
||||
* Factory methods for queries are called at rewrite time so they should be
|
||||
* cheap. In particular they should not read data from disk or perform a
|
||||
* network call. Furthermore they may only return a {@link MatchAllDocsQuery}
|
||||
* or a {@link MatchNoDocsQuery}.
|
||||
*/
|
||||
public abstract class ConstantFieldType extends MappedFieldType {
|
||||
|
||||
public ConstantFieldType() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ConstantFieldType(ConstantFieldType other) {
|
||||
super(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isSearchable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isAggregatable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query existsQuery(QueryShardContext context) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the constant value of this field matches the provided {@code pattern}
|
||||
* as documented in {@link Regex#simpleMatch}.
|
||||
*/
|
||||
protected abstract boolean matches(String pattern, QueryShardContext context);
|
||||
|
||||
private static String valueToString(Object value) {
|
||||
return value instanceof BytesRef
|
||||
? ((BytesRef) value).utf8ToString()
|
||||
: value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query termQuery(Object value, QueryShardContext context) {
|
||||
String pattern = valueToString(value);
|
||||
if (matches(pattern, context)) {
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return new MatchNoDocsQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query termsQuery(List<?> values, QueryShardContext context) {
|
||||
for (Object value : values) {
|
||||
String pattern = valueToString(value);
|
||||
if (matches(pattern, context)) {
|
||||
// `terms` queries are a disjunction, so one matching term is enough
|
||||
return Queries.newMatchAllQuery();
|
||||
}
|
||||
}
|
||||
return new MatchNoDocsQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query prefixQuery(String prefix,
|
||||
@Nullable MultiTermQuery.RewriteMethod method,
|
||||
QueryShardContext context) {
|
||||
String pattern = prefix + "*";
|
||||
if (matches(pattern, context)) {
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return new MatchNoDocsQuery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Query wildcardQuery(String value,
|
||||
@Nullable MultiTermQuery.RewriteMethod method,
|
||||
QueryShardContext context) {
|
||||
if (matches(value, context)) {
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return new MatchNoDocsQuery();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,13 +21,7 @@ package org.elasticsearch.index.mapper;
|
|||
|
||||
import org.apache.lucene.index.IndexOptions;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||
|
@ -89,7 +83,7 @@ public class IndexFieldMapper extends MetadataFieldMapper {
|
|||
}
|
||||
}
|
||||
|
||||
static final class IndexFieldType extends MappedFieldType {
|
||||
static final class IndexFieldType extends ConstantFieldType {
|
||||
|
||||
IndexFieldType() {}
|
||||
|
||||
|
@ -108,81 +102,8 @@ public class IndexFieldMapper extends MetadataFieldMapper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isSearchable() {
|
||||
// The _index field is always searchable.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
return new MatchAllDocsQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* This termQuery impl looks at the context to determine the index that
|
||||
* is being queried and then returns a MATCH_ALL_QUERY or MATCH_NO_QUERY
|
||||
* if the value matches this index. This can be useful if aliases or
|
||||
* wildcards are used but the aim is to restrict the query to specific
|
||||
* indices
|
||||
*/
|
||||
@Override
|
||||
public Query termQuery(Object value, @Nullable QueryShardContext context) {
|
||||
String pattern = value instanceof BytesRef
|
||||
? ((BytesRef) value).utf8ToString()
|
||||
: value.toString();
|
||||
if (context.indexMatches(pattern)) {
|
||||
// No need to OR these clauses - we can only logically be
|
||||
// running in the context of just one of these index names.
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return Queries.newMatchNoDocsQuery("The index [" + context.getFullyQualifiedIndex().getName() +
|
||||
"] doesn't match the provided value [" + value + "].");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query termsQuery(List values, QueryShardContext context) {
|
||||
if (context == null) {
|
||||
return super.termsQuery(values, context);
|
||||
}
|
||||
for (Object value : values) {
|
||||
String pattern = value instanceof BytesRef
|
||||
? ((BytesRef) value).utf8ToString()
|
||||
: value.toString();
|
||||
if (context.indexMatches(pattern)) {
|
||||
// No need to OR these clauses - we can only logically be
|
||||
// running in the context of just one of these index names.
|
||||
return Queries.newMatchAllQuery();
|
||||
}
|
||||
}
|
||||
// None of the listed index names are this one
|
||||
return Queries.newMatchNoDocsQuery("The index [" + context.getFullyQualifiedIndex().getName() +
|
||||
"] doesn't match the provided values [" + values + "].");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query prefixQuery(String value,
|
||||
@Nullable MultiTermQuery.RewriteMethod method,
|
||||
QueryShardContext context) {
|
||||
String pattern = value + "*";
|
||||
if (context.indexMatches(pattern)) {
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return Queries.newMatchNoDocsQuery("The index [" + context.getFullyQualifiedIndex().getName() +
|
||||
"] doesn't match the provided prefix [" + value + "].");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query wildcardQuery(String value,
|
||||
@Nullable MultiTermQuery.RewriteMethod method,
|
||||
QueryShardContext context) {
|
||||
if (context.indexMatches(value)) {
|
||||
return Queries.newMatchAllQuery();
|
||||
} else {
|
||||
return Queries.newMatchNoDocsQuery("The index [" + context.getFullyQualifiedIndex().getName()
|
||||
+ "] doesn't match the provided pattern [" + value + "].");
|
||||
}
|
||||
protected boolean matches(String pattern, QueryShardContext context) {
|
||||
return context.indexMatches(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.spans.SpanBoostQuery;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
|
@ -103,7 +104,7 @@ public abstract class AbstractQueryBuilder<QB extends AbstractQueryBuilder<QB>>
|
|||
if (boost != DEFAULT_BOOST) {
|
||||
if (query instanceof SpanQuery) {
|
||||
query = new SpanBoostQuery((SpanQuery) query, boost);
|
||||
} else {
|
||||
} else if (query instanceof MatchNoDocsQuery == false) {
|
||||
query = new BoostQuery(query, boost);
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +233,7 @@ public abstract class AbstractQueryBuilder<QB extends AbstractQueryBuilder<QB>>
|
|||
IOException {
|
||||
List<Query> queries = new ArrayList<>(queryBuilders.size());
|
||||
for (QueryBuilder queryBuilder : queryBuilders) {
|
||||
Query query = queryBuilder.toQuery(context);
|
||||
Query query = queryBuilder.rewrite(context).toQuery(context);
|
||||
if (query != null) {
|
||||
queries.add(query);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.FuzzyQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
@ -28,7 +27,6 @@ import org.elasticsearch.common.ParsingException;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.unit.Fuzziness;
|
||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -322,18 +320,26 @@ public class FuzzyQueryBuilder extends AbstractQueryBuilder<FuzzyQueryBuilder> i
|
|||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null) {
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
if (fieldType == null) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
}
|
||||
return super.doRewrite(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
Query query = null;
|
||||
String rewrite = this.rewrite;
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
if (fieldType != null) {
|
||||
query = fieldType.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions, context);
|
||||
}
|
||||
if (query == null) {
|
||||
int maxEdits = fuzziness.asDistance(BytesRefs.toString(value));
|
||||
query = new FuzzyQuery(new Term(fieldName, BytesRefs.toBytesRef(value)), maxEdits, prefixLength, maxExpansions, transpositions);
|
||||
if (fieldType == null) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
String rewrite = this.rewrite;
|
||||
Query query = fieldType.fuzzyQuery(value, fuzziness, prefixLength, maxExpansions, transpositions, context);
|
||||
if (query instanceof MultiTermQuery) {
|
||||
MultiTermQuery.RewriteMethod rewriteMethod = QueryParsers.parseRewriteMethod(rewrite, null,
|
||||
LoggingDeprecationHandler.INSTANCE);
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
@ -169,31 +168,39 @@ public class IdsQueryBuilder extends AbstractQueryBuilder<IdsQueryBuilder> {
|
|||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
if (ids.isEmpty()) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null && context.fieldMapper(IdFieldMapper.NAME) == null) {
|
||||
// no mappings yet
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
return super.doRewrite(queryRewriteContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
MappedFieldType idField = context.fieldMapper(IdFieldMapper.NAME);
|
||||
if (idField == null) {
|
||||
return new MatchNoDocsQuery("No mappings");
|
||||
if (idField == null || ids.isEmpty()) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
if (this.ids.isEmpty()) {
|
||||
return Queries.newMatchNoDocsQuery("Missing ids in \"" + this.getName() + "\" query.");
|
||||
final DocumentMapper mapper = context.getMapperService().documentMapper();
|
||||
Collection<String> typesForQuery;
|
||||
if (types.length == 0) {
|
||||
typesForQuery = context.queryTypes();
|
||||
} else if (types.length == 1 && MetaData.ALL.equals(types[0])) {
|
||||
typesForQuery = Collections.singleton(mapper.type());
|
||||
} else {
|
||||
final DocumentMapper mapper = context.getMapperService().documentMapper();
|
||||
Collection<String> typesForQuery;
|
||||
if (types.length == 0) {
|
||||
typesForQuery = context.queryTypes();
|
||||
} else if (types.length == 1 && MetaData.ALL.equals(types[0])) {
|
||||
typesForQuery = Collections.singleton(mapper.type());
|
||||
} else {
|
||||
typesForQuery = new HashSet<>(Arrays.asList(types));
|
||||
}
|
||||
typesForQuery = new HashSet<>(Arrays.asList(types));
|
||||
}
|
||||
|
||||
if (typesForQuery.contains(mapper.type())) {
|
||||
return idField.termsQuery(new ArrayList<>(ids), context);
|
||||
} else {
|
||||
return new MatchNoDocsQuery("Type mismatch");
|
||||
}
|
||||
|
||||
if (typesForQuery.contains(mapper.type())) {
|
||||
return idField.termsQuery(new ArrayList<>(ids), context);
|
||||
} else {
|
||||
return new MatchNoDocsQuery("Type mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,20 +19,20 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.ConstantFieldType;
|
||||
import org.elasticsearch.index.query.support.QueryParsers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -171,14 +171,26 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
|||
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
if ("_index".equals(fieldName)) {
|
||||
// Special-case optimisation for canMatch phase:
|
||||
// We can skip querying this shard if the index name doesn't match the value of this query on the "_index" field.
|
||||
QueryShardContext shardContext = queryRewriteContext.convertToShardContext();
|
||||
if (shardContext != null && shardContext.indexMatches(value + "*") == false) {
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null) {
|
||||
MappedFieldType fieldType = context.fieldMapper(this.fieldName);
|
||||
if (fieldType == null) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
} else if (fieldType instanceof ConstantFieldType) {
|
||||
// This logic is correct for all field types, but by only applying it to constant
|
||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||
// since rewrites might happen on a network thread.
|
||||
Query query = fieldType.prefixQuery(value, null, context); // the rewrite method doesn't matter
|
||||
if (query instanceof MatchAllDocsQuery) {
|
||||
return new MatchAllQueryBuilder();
|
||||
} else if (query instanceof MatchNoDocsQuery) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
} else {
|
||||
assert false : "Constant fields must produce match-all or match-none queries, got " + query ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.doRewrite(queryRewriteContext);
|
||||
}
|
||||
|
||||
|
@ -186,20 +198,11 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder>
|
|||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(rewrite, null, LoggingDeprecationHandler.INSTANCE);
|
||||
|
||||
Query query = null;
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
if (fieldType != null) {
|
||||
query = fieldType.prefixQuery(value, method, context);
|
||||
if (fieldType == null) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
if (query == null) {
|
||||
PrefixQuery prefixQuery = new PrefixQuery(new Term(fieldName, BytesRefs.toBytesRef(value)));
|
||||
if (method != null) {
|
||||
prefixQuery.setRewriteMethod(method);
|
||||
}
|
||||
query = prefixQuery;
|
||||
}
|
||||
|
||||
return query;
|
||||
return fieldType.prefixQuery(value, method, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.elasticsearch.index.query;
|
|||
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermRangeQuery;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
|
@ -29,14 +28,12 @@ import org.elasticsearch.common.Strings;
|
|||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.time.DateFormatter;
|
||||
import org.elasticsearch.common.time.DateMathParser;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.DateTimeException;
|
||||
|
@ -432,21 +429,23 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i
|
|||
// Overridable for testing only
|
||||
protected MappedFieldType.Relation getRelation(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
QueryShardContext shardContext = queryRewriteContext.convertToShardContext();
|
||||
// If the context is null we are not on the shard and cannot
|
||||
// rewrite so just pretend there is an intersection so that the rewrite is a noop
|
||||
if (shardContext == null || shardContext.getIndexReader() == null) {
|
||||
return MappedFieldType.Relation.INTERSECTS;
|
||||
}
|
||||
final MapperService mapperService = shardContext.getMapperService();
|
||||
final MappedFieldType fieldType = mapperService.fieldType(fieldName);
|
||||
if (fieldType == null) {
|
||||
// no field means we have no values
|
||||
return MappedFieldType.Relation.DISJOINT;
|
||||
} else {
|
||||
if (shardContext != null) {
|
||||
final MappedFieldType fieldType = shardContext.fieldMapper(fieldName);
|
||||
if (fieldType == null) {
|
||||
return MappedFieldType.Relation.DISJOINT;
|
||||
}
|
||||
if (shardContext.getIndexReader() == null) {
|
||||
// No reader, this may happen e.g. for percolator queries.
|
||||
return MappedFieldType.Relation.INTERSECTS;
|
||||
}
|
||||
|
||||
DateMathParser dateMathParser = getForceDateParser();
|
||||
return fieldType.isFieldWithinQuery(shardContext.getIndexReader(), from, to, includeLower,
|
||||
includeUpper, timeZone, dateMathParser, queryRewriteContext);
|
||||
}
|
||||
|
||||
// Not on the shard, we have no way to know what the relation is.
|
||||
return MappedFieldType.Relation.INTERSECTS;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -490,26 +489,14 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i
|
|||
return ExistsQueryBuilder.newFilter(context, fieldName);
|
||||
}
|
||||
}
|
||||
Query query = null;
|
||||
MappedFieldType mapper = context.fieldMapper(this.fieldName);
|
||||
if (mapper != null) {
|
||||
DateMathParser forcedDateParser = getForceDateParser();
|
||||
query = mapper.rangeQuery(
|
||||
from, to, includeLower, includeUpper,
|
||||
relation, timeZone, forcedDateParser, context);
|
||||
} else {
|
||||
if (timeZone != null) {
|
||||
throw new QueryShardException(context, "[range] time_zone can not be applied to non unmapped field ["
|
||||
+ fieldName + "]");
|
||||
}
|
||||
if (mapper == null) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
|
||||
if (query == null) {
|
||||
query = new TermRangeQuery(this.fieldName,
|
||||
BytesRefs.toBytesRef(from), BytesRefs.toBytesRef(to),
|
||||
includeLower, includeUpper);
|
||||
}
|
||||
return query;
|
||||
DateMathParser forcedDateParser = getForceDateParser();
|
||||
return mapper.rangeQuery(
|
||||
from, to, includeLower, includeUpper,
|
||||
relation, timeZone, forcedDateParser, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -126,11 +126,16 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
if (multiTermQueryBuilder instanceof PrefixQueryBuilder) {
|
||||
// We do the rewrite in toQuery to not have to deal with the case when a multi-term builder rewrites to a non-multi-term
|
||||
// builder.
|
||||
QueryBuilder multiTermQueryBuilder = Rewriteable.rewrite(this.multiTermQueryBuilder, context);
|
||||
if (multiTermQueryBuilder instanceof MatchNoneQueryBuilder) {
|
||||
return new SpanMatchNoDocsQuery(this.multiTermQueryBuilder.fieldName(), "Inner query rewrote to match_none");
|
||||
} else if (multiTermQueryBuilder instanceof PrefixQueryBuilder) {
|
||||
PrefixQueryBuilder prefixBuilder = (PrefixQueryBuilder) multiTermQueryBuilder;
|
||||
MappedFieldType fieldType = context.fieldMapper(multiTermQueryBuilder.fieldName());
|
||||
MappedFieldType fieldType = context.fieldMapper(prefixBuilder.fieldName());
|
||||
if (fieldType == null) {
|
||||
return new SpanMatchNoDocsQuery(multiTermQueryBuilder.fieldName(), "unknown field");
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
final SpanMultiTermQueryWrapper.SpanRewriteMethod spanRewriteMethod;
|
||||
if (prefixBuilder.rewrite() != null) {
|
||||
|
@ -159,7 +164,7 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer
|
|||
}
|
||||
}
|
||||
if (subQuery instanceof MatchNoDocsQuery) {
|
||||
return new SpanMatchNoDocsQuery(multiTermQueryBuilder.fieldName(), subQuery.toString());
|
||||
return new SpanMatchNoDocsQuery(this.multiTermQueryBuilder.fieldName(), subQuery.toString());
|
||||
} else if (subQuery instanceof MultiTermQuery == false) {
|
||||
throw new UnsupportedOperationException("unsupported inner query, should be "
|
||||
+ MultiTermQuery.class.getName() + " but was " + subQuery.getClass().getName());
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.ConstantFieldType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -132,28 +132,35 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> {
|
|||
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
if ("_index".equals(fieldName)) {
|
||||
// Special-case optimisation for canMatch phase:
|
||||
// We can skip querying this shard if the index name doesn't match the value of this query on the "_index" field.
|
||||
QueryShardContext shardContext = queryRewriteContext.convertToShardContext();
|
||||
if (shardContext != null && shardContext.indexMatches(BytesRefs.toString(value)) == false) {
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null) {
|
||||
MappedFieldType fieldType = context.fieldMapper(this.fieldName);
|
||||
if (fieldType == null) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
} else if (fieldType instanceof ConstantFieldType) {
|
||||
// This logic is correct for all field types, but by only applying it to constant
|
||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||
// since rewrites might happen on a network thread.
|
||||
Query query = fieldType.termQuery(value, context);
|
||||
if (query instanceof MatchAllDocsQuery) {
|
||||
return new MatchAllQueryBuilder();
|
||||
} else if (query instanceof MatchNoDocsQuery) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
} else {
|
||||
assert false : "Constant fields must produce match-all or match-none queries, got " + query ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.doRewrite(queryRewriteContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
Query query = null;
|
||||
MappedFieldType mapper = context.fieldMapper(this.fieldName);
|
||||
if (mapper != null) {
|
||||
query = mapper.termQuery(this.value, context);
|
||||
if (mapper == null) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
if (query == null) {
|
||||
query = new TermQuery(new Term(this.fieldName, BytesRefs.toBytesRef(this.value)));
|
||||
}
|
||||
return query;
|
||||
return mapper.termQuery(this.value, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermInSetQuery;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.BytesRefBuilder;
|
||||
import org.apache.lucene.util.SetOnce;
|
||||
|
@ -35,13 +36,12 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
|||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.index.IndexSettings;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.ConstantFieldType;
|
||||
import org.elasticsearch.indices.TermsLookup;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -432,12 +432,9 @@ public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> {
|
|||
|
||||
@Override
|
||||
protected Query doToQuery(QueryShardContext context) throws IOException {
|
||||
if (termsLookup != null || supplier != null) {
|
||||
if (termsLookup != null || supplier != null || values == null || values.isEmpty()) {
|
||||
throw new UnsupportedOperationException("query must be rewritten first");
|
||||
}
|
||||
if (values == null || values.isEmpty()) {
|
||||
return Queries.newMatchNoDocsQuery("No terms supplied for \"" + getName() + "\" query.");
|
||||
}
|
||||
int maxTermsCount = context.getIndexSettings().getMaxTermsCount();
|
||||
if (values.size() > maxTermsCount){
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -446,16 +443,10 @@ public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> {
|
|||
IndexSettings.MAX_TERMS_COUNT_SETTING.getKey() + "] index level setting.");
|
||||
}
|
||||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
|
||||
if (fieldType != null) {
|
||||
return fieldType.termsQuery(values, context);
|
||||
} else {
|
||||
BytesRef[] filterValues = new BytesRef[values.size()];
|
||||
for (int i = 0; i < filterValues.length; i++) {
|
||||
filterValues[i] = BytesRefs.toBytesRef(values.get(i));
|
||||
}
|
||||
return new TermInSetQuery(fieldName, filterValues);
|
||||
if (fieldType == null) {
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
return fieldType.termsQuery(values, context);
|
||||
}
|
||||
|
||||
private void fetch(TermsLookup termsLookup, Client client, ActionListener<List<Object>> actionListener) {
|
||||
|
@ -499,21 +490,31 @@ public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> {
|
|||
})));
|
||||
return new TermsQueryBuilder(this.fieldName, supplier::get);
|
||||
}
|
||||
if ("_index".equals(this.fieldName) && values != null) {
|
||||
// Special-case optimisation for canMatch phase:
|
||||
// We can skip querying this shard if the index name doesn't match any of the search terms.
|
||||
QueryShardContext shardContext = queryRewriteContext.convertToShardContext();
|
||||
if (shardContext != null) {
|
||||
for (Object localValue : values) {
|
||||
if (shardContext.indexMatches(BytesRefs.toString(localValue))) {
|
||||
// We can match - at least one index name matches
|
||||
return this;
|
||||
}
|
||||
}
|
||||
// all index names are invalid - no possibility of a match on this shard.
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null) {
|
||||
MappedFieldType fieldType = context.fieldMapper(this.fieldName);
|
||||
if (fieldType == null) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
} else if (fieldType instanceof ConstantFieldType) {
|
||||
// This logic is correct for all field types, but by only applying it to constant
|
||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||
// since rewrites might happen on a network thread.
|
||||
Query query = fieldType.termsQuery(values, context);
|
||||
if (query instanceof MatchAllDocsQuery) {
|
||||
return new MatchAllQueryBuilder();
|
||||
} else if (query instanceof MatchNoDocsQuery) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
} else {
|
||||
assert false : "Constant fields must produce match-all or match-none queries, got " + query ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
|
@ -27,11 +28,11 @@ import org.elasticsearch.common.ParsingException;
|
|||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.ConstantFieldType;
|
||||
import org.elasticsearch.index.query.support.QueryParsers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -182,14 +183,26 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
|||
|
||||
@Override
|
||||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
|
||||
if ("_index".equals(fieldName)) {
|
||||
// Special-case optimisation for canMatch phase:
|
||||
// We can skip querying this shard if the index name doesn't match the value of this query on the "_index" field.
|
||||
QueryShardContext shardContext = queryRewriteContext.convertToShardContext();
|
||||
if (shardContext != null && shardContext.indexMatches(BytesRefs.toString(value)) == false) {
|
||||
QueryShardContext context = queryRewriteContext.convertToShardContext();
|
||||
if (context != null) {
|
||||
MappedFieldType fieldType = context.fieldMapper(this.fieldName);
|
||||
if (fieldType == null) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
}
|
||||
} else if (fieldType instanceof ConstantFieldType) {
|
||||
// This logic is correct for all field types, but by only applying it to constant
|
||||
// fields we also have the guarantee that it doesn't perform I/O, which is important
|
||||
// since rewrites might happen on a network thread.
|
||||
Query query = fieldType.wildcardQuery(value, null, context); // the rewrite method doesn't matter
|
||||
if (query instanceof MatchAllDocsQuery) {
|
||||
return new MatchAllQueryBuilder();
|
||||
} else if (query instanceof MatchNoDocsQuery) {
|
||||
return new MatchNoneQueryBuilder();
|
||||
} else {
|
||||
assert false : "Constant fields must produce match-all or match-none queries, got " + query ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.doRewrite(queryRewriteContext);
|
||||
}
|
||||
|
||||
|
@ -198,7 +211,7 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil
|
|||
MappedFieldType fieldType = context.fieldMapper(fieldName);
|
||||
|
||||
if (fieldType == null) {
|
||||
return new MatchNoDocsQuery("unknown field [" + fieldName + "]");
|
||||
throw new IllegalStateException("Rewrite first");
|
||||
}
|
||||
|
||||
MultiTermQuery.RewriteMethod method = QueryParsers.parseRewriteMethod(
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
|
||||
|
@ -127,10 +128,23 @@ public class SignificantTermsAggregationBuilder extends ValuesSourceAggregationB
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AggregationBuilder shallowCopy(Builder factoriesBuilder, Map<String, Object> metaData) {
|
||||
protected SignificantTermsAggregationBuilder shallowCopy(Builder factoriesBuilder, Map<String, Object> metaData) {
|
||||
return new SignificantTermsAggregationBuilder(this, factoriesBuilder, metaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AggregationBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException {
|
||||
if (filterBuilder != null) {
|
||||
QueryBuilder rewrittenFilter = filterBuilder.rewrite(queryShardContext);
|
||||
if (rewrittenFilter != filterBuilder) {
|
||||
SignificantTermsAggregationBuilder rewritten = shallowCopy(factoriesBuilder, metaData);
|
||||
rewritten.backgroundFilter(rewrittenFilter);
|
||||
return rewritten;
|
||||
}
|
||||
}
|
||||
return super.doRewrite(queryShardContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void innerWriteTo(StreamOutput out) throws IOException {
|
||||
bucketCountThresholds.writeTo(out);
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.query;
|
|||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
|
@ -85,7 +86,7 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
|
||||
if (clauses.isEmpty()) {
|
||||
assertThat(query, instanceOf(MatchAllDocsQuery.class));
|
||||
} else {
|
||||
} else if (query instanceof MatchNoDocsQuery == false) {
|
||||
assertThat(query, instanceOf(BooleanQuery.class));
|
||||
BooleanQuery booleanQuery = (BooleanQuery) query;
|
||||
if (queryBuilder.adjustPureNegative()) {
|
||||
|
@ -113,7 +114,7 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
BooleanClause.Occur occur, QueryShardContext context) throws IOException {
|
||||
List<BooleanClause> clauses = new ArrayList<>();
|
||||
for (QueryBuilder query : queryBuilders) {
|
||||
Query innerQuery = query.toQuery(context);
|
||||
Query innerQuery = query.rewrite(context).toQuery(context);
|
||||
if (innerQuery != null) {
|
||||
clauses.add(new BooleanClause(innerQuery, occur));
|
||||
}
|
||||
|
@ -195,15 +196,15 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
public void testMinShouldMatchBiggerThanNumberOfShouldClauses() throws Exception {
|
||||
BooleanQuery bq = (BooleanQuery) parseQuery(
|
||||
boolQuery()
|
||||
.should(termQuery("foo", "bar"))
|
||||
.should(termQuery("foo2", "bar2"))
|
||||
.should(termQuery(STRING_FIELD_NAME, "bar"))
|
||||
.should(termQuery(STRING_FIELD_NAME_2, "bar2"))
|
||||
.minimumShouldMatch("3")).toQuery(createShardContext());
|
||||
assertEquals(3, bq.getMinimumNumberShouldMatch());
|
||||
|
||||
bq = (BooleanQuery) parseQuery(
|
||||
boolQuery()
|
||||
.should(termQuery("foo", "bar"))
|
||||
.should(termQuery("foo2", "bar2"))
|
||||
.should(termQuery(STRING_FIELD_NAME, "bar"))
|
||||
.should(termQuery(STRING_FIELD_NAME_2, "bar2"))
|
||||
.minimumShouldMatch(3)).toQuery(createShardContext());
|
||||
assertEquals(3, bq.getMinimumNumberShouldMatch());
|
||||
}
|
||||
|
@ -211,8 +212,8 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
public void testMinShouldMatchDisableCoord() throws Exception {
|
||||
BooleanQuery bq = (BooleanQuery) parseQuery(
|
||||
boolQuery()
|
||||
.should(termQuery("foo", "bar"))
|
||||
.should(termQuery("foo2", "bar2"))
|
||||
.should(termQuery(STRING_FIELD_NAME, "bar"))
|
||||
.should(termQuery(STRING_FIELD_NAME, "bar2"))
|
||||
.minimumShouldMatch("3")).toQuery(createShardContext());
|
||||
assertEquals(3, bq.getMinimumNumberShouldMatch());
|
||||
}
|
||||
|
@ -292,22 +293,22 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
boolean mustRewrite = false;
|
||||
if (randomBoolean()) {
|
||||
mustRewrite = true;
|
||||
boolQueryBuilder.must(new WrapperQueryBuilder(new TermsQueryBuilder("foo", "must").toString()));
|
||||
boolQueryBuilder.must(new WrapperQueryBuilder(new TermsQueryBuilder(STRING_FIELD_NAME, "must").toString()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
mustRewrite = true;
|
||||
boolQueryBuilder.should(new WrapperQueryBuilder(new TermsQueryBuilder("foo", "should").toString()));
|
||||
boolQueryBuilder.should(new WrapperQueryBuilder(new TermsQueryBuilder(STRING_FIELD_NAME, "should").toString()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
mustRewrite = true;
|
||||
boolQueryBuilder.filter(new WrapperQueryBuilder(new TermsQueryBuilder("foo", "filter").toString()));
|
||||
boolQueryBuilder.filter(new WrapperQueryBuilder(new TermsQueryBuilder(STRING_FIELD_NAME, "filter").toString()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
mustRewrite = true;
|
||||
boolQueryBuilder.mustNot(new WrapperQueryBuilder(new TermsQueryBuilder("foo", "must_not").toString()));
|
||||
boolQueryBuilder.mustNot(new WrapperQueryBuilder(new TermsQueryBuilder(STRING_FIELD_NAME, "must_not").toString()));
|
||||
}
|
||||
if (mustRewrite == false && randomBoolean()) {
|
||||
boolQueryBuilder.must(new TermsQueryBuilder("foo", "no_rewrite"));
|
||||
boolQueryBuilder.must(new TermsQueryBuilder(STRING_FIELD_NAME, "no_rewrite"));
|
||||
}
|
||||
QueryBuilder rewritten = boolQueryBuilder.rewrite(createShardContext());
|
||||
if (mustRewrite == false && boolQueryBuilder.must().isEmpty()) {
|
||||
|
@ -318,16 +319,16 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
if (mustRewrite) {
|
||||
assertNotSame(rewrite, boolQueryBuilder);
|
||||
if (boolQueryBuilder.must().isEmpty() == false) {
|
||||
assertEquals(new TermsQueryBuilder("foo", "must"), rewrite.must().get(0));
|
||||
assertEquals(new TermsQueryBuilder(STRING_FIELD_NAME, "must"), rewrite.must().get(0));
|
||||
}
|
||||
if (boolQueryBuilder.should().isEmpty() == false) {
|
||||
assertEquals(new TermsQueryBuilder("foo", "should"), rewrite.should().get(0));
|
||||
assertEquals(new TermsQueryBuilder(STRING_FIELD_NAME, "should"), rewrite.should().get(0));
|
||||
}
|
||||
if (boolQueryBuilder.mustNot().isEmpty() == false) {
|
||||
assertEquals(new TermsQueryBuilder("foo", "must_not"), rewrite.mustNot().get(0));
|
||||
assertEquals(new TermsQueryBuilder(STRING_FIELD_NAME, "must_not"), rewrite.mustNot().get(0));
|
||||
}
|
||||
if (boolQueryBuilder.filter().isEmpty() == false) {
|
||||
assertEquals(new TermsQueryBuilder("foo", "filter"), rewrite.filter().get(0));
|
||||
assertEquals(new TermsQueryBuilder(STRING_FIELD_NAME, "filter"), rewrite.filter().get(0));
|
||||
}
|
||||
} else {
|
||||
assertSame(rewrite, boolQueryBuilder);
|
||||
|
@ -360,14 +361,14 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
||||
boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(new TermQueryBuilder("foo","bar"));
|
||||
boolQueryBuilder.must(new TermQueryBuilder(STRING_FIELD_NAME,"bar"));
|
||||
boolQueryBuilder.filter(new WrapperQueryBuilder(new WrapperQueryBuilder(new MatchNoneQueryBuilder().toString()).toString()));
|
||||
rewritten = boolQueryBuilder.rewrite(createShardContext());
|
||||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
||||
boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.must(new TermQueryBuilder("foo","bar"));
|
||||
boolQueryBuilder.filter(new BoolQueryBuilder().should(new TermQueryBuilder("foo","bar"))
|
||||
boolQueryBuilder.must(new TermQueryBuilder(STRING_FIELD_NAME,"bar"));
|
||||
boolQueryBuilder.filter(new BoolQueryBuilder().should(new TermQueryBuilder(STRING_FIELD_NAME,"bar"))
|
||||
.filter(new MatchNoneQueryBuilder()));
|
||||
rewritten = Rewriteable.rewrite(boolQueryBuilder, createShardContext());
|
||||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
@ -378,7 +379,7 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
assertEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
||||
boolQueryBuilder = new BoolQueryBuilder();
|
||||
boolQueryBuilder.should(new TermQueryBuilder("foo", "bar"));
|
||||
boolQueryBuilder.should(new TermQueryBuilder(STRING_FIELD_NAME, "bar"));
|
||||
boolQueryBuilder.should(new WrapperQueryBuilder(new MatchNoneQueryBuilder().toString()));
|
||||
rewritten = Rewriteable.rewrite(boolQueryBuilder, createShardContext());
|
||||
assertNotEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
|
@ -387,4 +388,16 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde
|
|||
rewritten = Rewriteable.rewrite(boolQueryBuilder, createShardContext());
|
||||
assertNotEquals(new MatchNoneQueryBuilder(), rewritten);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
TermQueryBuilder termQuery = new TermQueryBuilder("unmapped_field", 42);
|
||||
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
|
||||
boolQuery.must(termQuery);
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> boolQuery.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ public class BoostingQueryBuilderTests extends AbstractQueryTestCase<BoostingQue
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(BoostingQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
Query positive = queryBuilder.positiveQuery().toQuery(context);
|
||||
Query negative = queryBuilder.negativeQuery().toQuery(context);
|
||||
Query positive = queryBuilder.positiveQuery().rewrite(context).toQuery(context);
|
||||
Query negative = queryBuilder.negativeQuery().rewrite(context).toQuery(context);
|
||||
if (positive == null || negative == null) {
|
||||
assertThat(query, nullValue());
|
||||
} else {
|
||||
|
@ -103,4 +103,22 @@ public class BoostingQueryBuilderTests extends AbstractQueryTestCase<BoostingQue
|
|||
assertEquals(new BoostingQueryBuilder(positive.rewrite(createShardContext()), negative.rewrite(createShardContext())), rewrite);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
|
||||
BoostingQueryBuilder queryBuilder1 = new BoostingQueryBuilder(
|
||||
new TermQueryBuilder("unmapped_field", "foo"), new MatchNoneQueryBuilder());
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder1.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
|
||||
BoostingQueryBuilder queryBuilder2 = new BoostingQueryBuilder(
|
||||
new MatchAllQueryBuilder(), new TermQueryBuilder("unmapped_field", "foo"));
|
||||
e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder2.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||
|
@ -41,9 +42,11 @@ public class ConstantScoreQueryBuilderTests extends AbstractQueryTestCase<Consta
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(ConstantScoreQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
Query innerQuery = queryBuilder.innerQuery().toQuery(context);
|
||||
Query innerQuery = queryBuilder.innerQuery().rewrite(context).toQuery(context);
|
||||
if (innerQuery == null) {
|
||||
assertThat(query, nullValue());
|
||||
} else if (innerQuery instanceof MatchNoDocsQuery) {
|
||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||
} else {
|
||||
assertThat(query, instanceOf(ConstantScoreQuery.class));
|
||||
ConstantScoreQuery constantScoreQuery = (ConstantScoreQuery) query;
|
||||
|
@ -107,4 +110,14 @@ public class ConstantScoreQueryBuilderTests extends AbstractQueryTestCase<Consta
|
|||
QueryBuilder rewrite = constantScoreQueryBuilder.rewrite(createShardContext());
|
||||
assertEquals(rewrite, new MatchNoneQueryBuilder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
ConstantScoreQueryBuilder queryBuilder = new ConstantScoreQueryBuilder(new TermQueryBuilder("unmapped_field", "foo"));
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,4 +164,14 @@ public class IdsQueryBuilderTests extends AbstractQueryTestCase<IdsQueryBuilder>
|
|||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContextWithNoType();
|
||||
context.setAllowUnmappedFields(true);
|
||||
IdsQueryBuilder queryBuilder = createTestQueryBuilder();
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,8 +57,6 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBuilder> {
|
||||
|
||||
boolean requiresRewrite = false;
|
||||
|
||||
@Override
|
||||
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
|
||||
mapperService.merge("_doc", new CompressedXContent(Strings.toString(PutMappingRequest.buildFromSimplifiedDef("_doc",
|
||||
|
@ -79,10 +77,6 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu
|
|||
@Override
|
||||
protected NestedQueryBuilder doCreateTestQueryBuilder() {
|
||||
QueryBuilder innerQueryBuilder = RandomQueryBuilder.createQuery(random());
|
||||
if (randomBoolean()) {
|
||||
requiresRewrite = true;
|
||||
innerQueryBuilder = new WrapperQueryBuilder(innerQueryBuilder.toString());
|
||||
}
|
||||
NestedQueryBuilder nqb = new NestedQueryBuilder("nested1", innerQueryBuilder,
|
||||
RandomPicks.randomFrom(random(), ScoreMode.values()));
|
||||
nqb.ignoreUnmapped(randomBoolean());
|
||||
|
@ -186,13 +180,14 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu
|
|||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
try {
|
||||
super.testMustRewrite();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (requiresRewrite == false) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
TermQueryBuilder innerQueryBuilder = new TermQueryBuilder("nested1.unmapped_field", "foo");
|
||||
NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("nested1", innerQueryBuilder,
|
||||
RandomPicks.randomFrom(random(), ScoreMode.values()));
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> nestedQueryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
|
||||
public void testIgnoreUnmapped() throws IOException {
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
package org.elasticsearch.index.query;
|
||||
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.MultiTermQuery;
|
||||
import org.apache.lucene.search.PrefixQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
@ -68,12 +70,14 @@ public class PrefixQueryBuilderTests extends AbstractQueryTestCase<PrefixQueryBu
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(PrefixQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
assertThat(query, instanceOf(PrefixQuery.class));
|
||||
PrefixQuery prefixQuery = (PrefixQuery) query;
|
||||
assertThat(query, Matchers.anyOf(instanceOf(PrefixQuery.class), instanceOf(MatchNoDocsQuery.class)));
|
||||
if (context.fieldMapper(queryBuilder.fieldName()) != null) { // The field is mapped
|
||||
PrefixQuery prefixQuery = (PrefixQuery) query;
|
||||
|
||||
String expectedFieldName = expectedFieldName(queryBuilder.fieldName());
|
||||
assertThat(prefixQuery.getPrefix().field(), equalTo(expectedFieldName));
|
||||
assertThat(prefixQuery.getPrefix().text(), equalTo(queryBuilder.value()));
|
||||
String expectedFieldName = expectedFieldName(queryBuilder.fieldName());
|
||||
assertThat(prefixQuery.getPrefix().field(), equalTo(expectedFieldName));
|
||||
assertThat(prefixQuery.getPrefix().text(), equalTo(queryBuilder.value()));
|
||||
}
|
||||
}
|
||||
|
||||
public void testIllegalArguments() {
|
||||
|
@ -88,10 +92,10 @@ public class PrefixQueryBuilderTests extends AbstractQueryTestCase<PrefixQueryBu
|
|||
|
||||
public void testBlendedRewriteMethod() throws IOException {
|
||||
String rewrite = "top_terms_blended_freqs_10";
|
||||
Query parsedQuery = parseQuery(prefixQuery("field", "val").rewrite(rewrite)).toQuery(createShardContext());
|
||||
Query parsedQuery = parseQuery(prefixQuery(STRING_FIELD_NAME, "val").rewrite(rewrite)).toQuery(createShardContext());
|
||||
assertThat(parsedQuery, instanceOf(PrefixQuery.class));
|
||||
PrefixQuery prefixQuery = (PrefixQuery) parsedQuery;
|
||||
assertThat(prefixQuery.getPrefix(), equalTo(new Term("field", "val")));
|
||||
assertThat(prefixQuery.getPrefix(), equalTo(new Term(STRING_FIELD_NAME, "val")));
|
||||
assertThat(prefixQuery.getRewriteMethod(), instanceOf(MultiTermQuery.TopTermsBlendedFreqScoringRewrite.class));
|
||||
}
|
||||
|
||||
|
@ -153,7 +157,16 @@ public class PrefixQueryBuilderTests extends AbstractQueryTestCase<PrefixQueryBu
|
|||
PrefixQueryBuilder query = prefixQuery("_index", getIndex().getName());
|
||||
QueryShardContext queryShardContext = createShardContext();
|
||||
QueryBuilder rewritten = query.rewrite(queryShardContext);
|
||||
assertThat(rewritten, instanceOf(PrefixQueryBuilder.class));
|
||||
assertThat(rewritten, instanceOf(MatchAllQueryBuilder.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
PrefixQueryBuilder queryBuilder = new PrefixQueryBuilder("unmapped_field", "foo");
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,6 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
|
@ -245,16 +244,6 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase<RangeQueryBuil
|
|||
expectThrows(IllegalArgumentException.class, () -> rangeQueryBuilder.format("badFormat"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifying a timezone together with an unmapped field should throw an exception.
|
||||
*/
|
||||
public void testToQueryUnmappedWithTimezone() throws QueryShardException {
|
||||
RangeQueryBuilder query = new RangeQueryBuilder("bogus_field");
|
||||
query.from(1).to(10).timeZone("UTC");
|
||||
QueryShardException e = expectThrows(QueryShardException.class, () -> query.toQuery(createShardContext()));
|
||||
assertThat(e.getMessage(), containsString("[range] time_zone can not be applied"));
|
||||
}
|
||||
|
||||
public void testToQueryNumericField() throws IOException {
|
||||
Query parsedQuery = rangeQuery(INT_FIELD_NAME).from(23).to(54).includeLower(true).includeUpper(false).toQuery(createShardContext());
|
||||
// since age is automatically registered in data, we encode it as numeric
|
||||
|
|
|
@ -99,6 +99,19 @@ public class ScriptScoreQueryBuilderTests extends AbstractQueryTestCase<ScriptSc
|
|||
assertFalse("query should not be cacheable: " + queryBuilder.toString(), context.isCacheable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("unmapped_field", "foo");
|
||||
String scriptStr = "1";
|
||||
Script script = new Script(ScriptType.INLINE, MockScriptEngine.NAME, scriptStr, Collections.emptyMap());
|
||||
ScriptScoreQueryBuilder scriptScoreQueryBuilder = new ScriptScoreQueryBuilder(termQueryBuilder, script);
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> scriptScoreQueryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
|
||||
public void testDisallowExpensiveQueries() {
|
||||
QueryShardContext queryShardContext = mock(QueryShardContext.class);
|
||||
when(queryShardContext.allowExpensiveQueries()).thenReturn(false);
|
||||
|
|
|
@ -90,7 +90,8 @@ public class SpanMultiTermQueryBuilderTests extends AbstractQueryTestCase<SpanMu
|
|||
if (query instanceof SpanMatchNoDocsQuery) {
|
||||
return;
|
||||
}
|
||||
assertThat(query, either(instanceOf(SpanMultiTermQueryWrapper.class)).or(instanceOf(FieldMaskingSpanQuery.class)));
|
||||
assertThat(query, either(instanceOf(SpanMultiTermQueryWrapper.class))
|
||||
.or(instanceOf(FieldMaskingSpanQuery.class)));
|
||||
if (query instanceof SpanMultiTermQueryWrapper) {
|
||||
SpanMultiTermQueryWrapper wrapper = (SpanMultiTermQueryWrapper) query;
|
||||
Query innerQuery = queryBuilder.innerQuery().toQuery(context);
|
||||
|
|
|
@ -21,11 +21,11 @@ package org.elasticsearch.index.query;
|
|||
|
||||
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.PointRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.lucene.BytesRefs;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -91,7 +91,7 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
|
|||
|
||||
@Override
|
||||
protected void doAssertLuceneQuery(TermQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)));
|
||||
assertThat(query, either(instanceOf(TermQuery.class)).or(instanceOf(PointRangeQuery.class)).or(instanceOf(MatchNoDocsQuery.class)));
|
||||
MappedFieldType mapper = context.fieldMapper(queryBuilder.fieldName());
|
||||
if (query instanceof TermQuery) {
|
||||
TermQuery termQuery = (TermQuery) query;
|
||||
|
@ -99,14 +99,12 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
|
|||
String expectedFieldName = expectedFieldName(queryBuilder.fieldName());
|
||||
assertThat(termQuery.getTerm().field(), equalTo(expectedFieldName));
|
||||
|
||||
if (mapper != null) {
|
||||
Term term = ((TermQuery) mapper.termQuery(queryBuilder.value(), null)).getTerm();
|
||||
assertThat(termQuery.getTerm(), equalTo(term));
|
||||
} else {
|
||||
assertThat(termQuery.getTerm().bytes(), equalTo(BytesRefs.toBytesRef(queryBuilder.value())));
|
||||
}
|
||||
} else {
|
||||
Term term = ((TermQuery) mapper.termQuery(queryBuilder.value(), null)).getTerm();
|
||||
assertThat(termQuery.getTerm(), equalTo(term));
|
||||
} else if (mapper != null) {
|
||||
assertEquals(query, mapper.termQuery(queryBuilder.value(), null));
|
||||
} else {
|
||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,6 +183,16 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
|
|||
TermQueryBuilder query = QueryBuilders.termQuery("_index", getIndex().getName());
|
||||
QueryShardContext queryShardContext = createShardContext();
|
||||
QueryBuilder rewritten = query.rewrite(queryShardContext);
|
||||
assertThat(rewritten, instanceOf(TermQueryBuilder.class));
|
||||
}
|
||||
assertThat(rewritten, instanceOf(MatchAllQueryBuilder.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
TermQueryBuilder queryBuilder = new TermQueryBuilder("unmapped_field", "foo");
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,16 +112,13 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
|
|||
protected void doAssertLuceneQuery(TermsQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
if (queryBuilder.termsLookup() == null && (queryBuilder.values() == null || queryBuilder.values().isEmpty())) {
|
||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||
MatchNoDocsQuery matchNoDocsQuery = (MatchNoDocsQuery) query;
|
||||
assertThat(matchNoDocsQuery.toString(), containsString("No terms supplied for \"terms\" query."));
|
||||
} else if (queryBuilder.termsLookup() != null && randomTerms.size() == 0){
|
||||
assertThat(query, instanceOf(MatchNoDocsQuery.class));
|
||||
MatchNoDocsQuery matchNoDocsQuery = (MatchNoDocsQuery) query;
|
||||
assertThat(matchNoDocsQuery.toString(), containsString("No terms supplied for \"terms\" query."));
|
||||
} else {
|
||||
assertThat(query, either(instanceOf(TermInSetQuery.class))
|
||||
.or(instanceOf(PointInSetQuery.class))
|
||||
.or(instanceOf(ConstantScoreQuery.class)));
|
||||
.or(instanceOf(ConstantScoreQuery.class))
|
||||
.or(instanceOf(MatchNoDocsQuery.class)));
|
||||
if (query instanceof ConstantScoreQuery) {
|
||||
assertThat(((ConstantScoreQuery) query).getQuery(), instanceOf(BooleanQuery.class));
|
||||
}
|
||||
|
@ -141,8 +138,13 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
|
|||
}
|
||||
|
||||
String fieldName = expectedFieldName(queryBuilder.fieldName());
|
||||
TermInSetQuery expected = new TermInSetQuery(fieldName,
|
||||
terms.stream().filter(Objects::nonNull).map(Object::toString).map(BytesRef::new).collect(Collectors.toList()));
|
||||
Query expected;
|
||||
if (context.fieldMapper(fieldName) != null) {
|
||||
expected = new TermInSetQuery(fieldName,
|
||||
terms.stream().filter(Objects::nonNull).map(Object::toString).map(BytesRef::new).collect(Collectors.toList()));
|
||||
} else {
|
||||
expected = new MatchNoDocsQuery();
|
||||
}
|
||||
assertEquals(expected, query);
|
||||
}
|
||||
}
|
||||
|
@ -267,8 +269,16 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
|
|||
UnsupportedOperationException e = expectThrows(UnsupportedOperationException.class,
|
||||
() -> termsQueryBuilder.toQuery(createShardContext()));
|
||||
assertEquals("query must be rewritten first", e.getMessage());
|
||||
assertEquals(rewriteAndFetch(termsQueryBuilder, createShardContext()), new TermsQueryBuilder(STRING_FIELD_NAME,
|
||||
randomTerms.stream().filter(x -> x != null).collect(Collectors.toList()))); // terms lookup removes null values
|
||||
|
||||
// terms lookup removes null values
|
||||
List<Object> nonNullTerms = randomTerms.stream().filter(x -> x != null).collect(Collectors.toList());
|
||||
QueryBuilder expected;
|
||||
if (nonNullTerms.isEmpty()) {
|
||||
expected = new MatchNoneQueryBuilder();
|
||||
} else {
|
||||
expected = new TermsQueryBuilder(STRING_FIELD_NAME, nonNullTerms);
|
||||
}
|
||||
assertEquals(expected, rewriteAndFetch(termsQueryBuilder, createShardContext()));
|
||||
}
|
||||
|
||||
public void testGeo() throws Exception {
|
||||
|
@ -329,7 +339,7 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
|
|||
TermsQueryBuilder query = new TermsQueryBuilder("_index", "does_not_exist", getIndex().getName());
|
||||
QueryShardContext queryShardContext = createShardContext();
|
||||
QueryBuilder rewritten = query.rewrite(queryShardContext);
|
||||
assertThat(rewritten, instanceOf(TermsQueryBuilder.class));
|
||||
assertThat(rewritten, instanceOf(MatchAllQueryBuilder.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -343,4 +353,5 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
|
|||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -152,6 +152,16 @@ public class WildcardQueryBuilderTests extends AbstractQueryTestCase<WildcardQue
|
|||
WildcardQueryBuilder query = new WildcardQueryBuilder("_index", firstHalfOfIndexName +"*");
|
||||
QueryShardContext queryShardContext = createShardContext();
|
||||
QueryBuilder rewritten = query.rewrite(queryShardContext);
|
||||
assertThat(rewritten, instanceOf(WildcardQueryBuilder.class));
|
||||
}
|
||||
assertThat(rewritten, instanceOf(MatchAllQueryBuilder.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
WildcardQueryBuilder queryBuilder = new WildcardQueryBuilder("unmapped_field", "foo");
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ public class WrapperQueryBuilderTests extends AbstractQueryTestCase<WrapperQuery
|
|||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
TermQueryBuilder tqb = new TermQueryBuilder("foo", "bar");
|
||||
TermQueryBuilder tqb = new TermQueryBuilder(STRING_FIELD_NAME, "bar");
|
||||
WrapperQueryBuilder qb = new WrapperQueryBuilder(tqb.toString());
|
||||
UnsupportedOperationException e = expectThrows(UnsupportedOperationException.class, () -> qb.toQuery(createShardContext()));
|
||||
assertEquals("this query must be rewritten first", e.getMessage());
|
||||
|
@ -137,7 +137,7 @@ public class WrapperQueryBuilderTests extends AbstractQueryTestCase<WrapperQuery
|
|||
}
|
||||
|
||||
public void testRewriteWithInnerBoost() throws IOException {
|
||||
final TermQueryBuilder query = new TermQueryBuilder("foo", "bar").boost(2);
|
||||
final TermQueryBuilder query = new TermQueryBuilder(STRING_FIELD_NAME, "bar").boost(2);
|
||||
QueryBuilder builder = new WrapperQueryBuilder(query.toString());
|
||||
QueryShardContext shardContext = createShardContext();
|
||||
assertEquals(query, builder.rewrite(shardContext));
|
||||
|
@ -149,15 +149,15 @@ public class WrapperQueryBuilderTests extends AbstractQueryTestCase<WrapperQuery
|
|||
QueryShardContext shardContext = createShardContext();
|
||||
|
||||
QueryBuilder qb = new WrapperQueryBuilder(
|
||||
new WrapperQueryBuilder(new TermQueryBuilder("foo", "bar").toString()).toString()
|
||||
new WrapperQueryBuilder(new TermQueryBuilder(STRING_FIELD_NAME, "bar").toString()).toString()
|
||||
);
|
||||
assertEquals(new TermQuery(new Term("foo", "bar")), qb.rewrite(shardContext).toQuery(shardContext));
|
||||
assertEquals(new TermQuery(new Term(STRING_FIELD_NAME, "bar")), qb.rewrite(shardContext).toQuery(shardContext));
|
||||
qb = new WrapperQueryBuilder(
|
||||
new WrapperQueryBuilder(
|
||||
new WrapperQueryBuilder(new TermQueryBuilder("foo", "bar").toString()).toString()
|
||||
new WrapperQueryBuilder(new TermQueryBuilder(STRING_FIELD_NAME, "bar").toString()).toString()
|
||||
).toString()
|
||||
);
|
||||
assertEquals(new TermQuery(new Term("foo", "bar")), qb.rewrite(shardContext).toQuery(shardContext));
|
||||
assertEquals(new TermQuery(new Term(STRING_FIELD_NAME, "bar")), qb.rewrite(shardContext).toQuery(shardContext));
|
||||
|
||||
qb = new WrapperQueryBuilder(new BoolQueryBuilder().toString());
|
||||
assertEquals(new MatchAllDocsQuery(), qb.rewrite(shardContext).toQuery(shardContext));
|
||||
|
|
|
@ -552,11 +552,12 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
|
|||
}
|
||||
|
||||
public void testCustomWeightFactorQueryBuilderWithFunctionScore() throws IOException {
|
||||
Query parsedQuery = parseQuery(functionScoreQuery(termQuery("name.last", "banon"), weightFactorFunction(1.3f)))
|
||||
.toQuery(createShardContext());
|
||||
QueryShardContext context = createShardContext();
|
||||
Query parsedQuery = parseQuery(functionScoreQuery(termQuery(STRING_FIELD_NAME_2, "banon"), weightFactorFunction(1.3f)))
|
||||
.rewrite(context).toQuery(context);
|
||||
assertThat(parsedQuery, instanceOf(FunctionScoreQuery.class));
|
||||
FunctionScoreQuery functionScoreQuery = (FunctionScoreQuery) parsedQuery;
|
||||
assertThat(((TermQuery) functionScoreQuery.getSubQuery()).getTerm(), equalTo(new Term("name.last", "banon")));
|
||||
assertThat(((TermQuery) functionScoreQuery.getSubQuery()).getTerm(), equalTo(new Term(STRING_FIELD_NAME_2, "banon")));
|
||||
assertThat((double) (functionScoreQuery.getFunctions()[0]).getWeight(), closeTo(1.3, 0.001));
|
||||
}
|
||||
|
||||
|
@ -642,14 +643,14 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
|
|||
|
||||
public void testRewrite() throws IOException {
|
||||
FunctionScoreQueryBuilder functionScoreQueryBuilder =
|
||||
new FunctionScoreQueryBuilder(new WrapperQueryBuilder(new TermQueryBuilder("foo", "bar").toString()))
|
||||
new FunctionScoreQueryBuilder(new WrapperQueryBuilder(new TermQueryBuilder(STRING_FIELD_NAME, "bar").toString()))
|
||||
.boostMode(CombineFunction.REPLACE)
|
||||
.scoreMode(FunctionScoreQuery.ScoreMode.SUM)
|
||||
.setMinScore(1)
|
||||
.maxBoost(100);
|
||||
FunctionScoreQueryBuilder rewrite = (FunctionScoreQueryBuilder) functionScoreQueryBuilder.rewrite(createShardContext());
|
||||
assertNotSame(functionScoreQueryBuilder, rewrite);
|
||||
assertEquals(rewrite.query(), new TermQueryBuilder("foo", "bar"));
|
||||
assertEquals(rewrite.query(), new TermQueryBuilder(STRING_FIELD_NAME, "bar"));
|
||||
assertEquals(rewrite.boostMode(), CombineFunction.REPLACE);
|
||||
assertEquals(rewrite.scoreMode(), FunctionScoreQuery.ScoreMode.SUM);
|
||||
assertEquals(rewrite.getMinScore(), 1f, 0.0001);
|
||||
|
@ -657,18 +658,18 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
|
|||
}
|
||||
|
||||
public void testRewriteWithFunction() throws IOException {
|
||||
QueryBuilder firstFunction = new WrapperQueryBuilder(new TermQueryBuilder("tq", "1").toString());
|
||||
TermQueryBuilder secondFunction = new TermQueryBuilder("tq", "2");
|
||||
QueryBuilder queryBuilder = randomBoolean() ? new WrapperQueryBuilder(new TermQueryBuilder("foo", "bar").toString())
|
||||
: new TermQueryBuilder("foo", "bar");
|
||||
QueryBuilder firstFunction = new WrapperQueryBuilder(new TermQueryBuilder(STRING_FIELD_NAME_2, "1").toString());
|
||||
TermQueryBuilder secondFunction = new TermQueryBuilder(STRING_FIELD_NAME_2, "2");
|
||||
QueryBuilder queryBuilder = randomBoolean() ? new WrapperQueryBuilder(new TermQueryBuilder(STRING_FIELD_NAME, "bar").toString())
|
||||
: new TermQueryBuilder(STRING_FIELD_NAME, "bar");
|
||||
FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(queryBuilder,
|
||||
new FunctionScoreQueryBuilder.FilterFunctionBuilder[] {
|
||||
new FunctionScoreQueryBuilder.FilterFunctionBuilder(firstFunction, new RandomScoreFunctionBuilder()),
|
||||
new FunctionScoreQueryBuilder.FilterFunctionBuilder(secondFunction, new RandomScoreFunctionBuilder()) });
|
||||
FunctionScoreQueryBuilder rewrite = (FunctionScoreQueryBuilder) functionScoreQueryBuilder.rewrite(createShardContext());
|
||||
assertNotSame(functionScoreQueryBuilder, rewrite);
|
||||
assertEquals(rewrite.query(), new TermQueryBuilder("foo", "bar"));
|
||||
assertEquals(rewrite.filterFunctionBuilders()[0].getFilter(), new TermQueryBuilder("tq", "1"));
|
||||
assertEquals(rewrite.query(), new TermQueryBuilder(STRING_FIELD_NAME, "bar"));
|
||||
assertEquals(rewrite.filterFunctionBuilders()[0].getFilter(), new TermQueryBuilder(STRING_FIELD_NAME_2, "1"));
|
||||
assertSame(rewrite.filterFunctionBuilders()[1].getFilter(), secondFunction);
|
||||
}
|
||||
|
||||
|
@ -685,7 +686,8 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
|
|||
builder.boostMode(randomFrom(CombineFunction.values()));
|
||||
}
|
||||
|
||||
Query query = builder.toQuery(createShardContext());
|
||||
QueryShardContext shardContext = createShardContext();
|
||||
Query query = builder.rewrite(shardContext).toQuery(shardContext);
|
||||
assertThat(query, instanceOf(FunctionScoreQuery.class));
|
||||
|
||||
CombineFunction expectedBoostMode = builder.boostMode() != null
|
||||
|
@ -840,4 +842,27 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("unmapped_field", "foo");
|
||||
|
||||
// main query needs rewriting
|
||||
FunctionScoreQueryBuilder functionQueryBuilder1 = new FunctionScoreQueryBuilder(termQueryBuilder);
|
||||
functionQueryBuilder1.setMinScore(1);
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> functionQueryBuilder1.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
|
||||
// filter needs rewriting
|
||||
FunctionScoreQueryBuilder functionQueryBuilder2 = new FunctionScoreQueryBuilder(new MatchAllQueryBuilder(),
|
||||
new FilterFunctionBuilder[] {
|
||||
new FilterFunctionBuilder(termQueryBuilder, new RandomScoreFunctionBuilder())
|
||||
});
|
||||
e = expectThrows(IllegalStateException.class,
|
||||
() -> functionQueryBuilder2.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -683,13 +683,15 @@ public class TermsAggregatorTests extends AggregatorTestCase {
|
|||
}
|
||||
|
||||
if (multiValued == false) {
|
||||
MappedFieldType filterFieldType = new KeywordFieldMapper.KeywordFieldType();
|
||||
filterFieldType.setName("include");
|
||||
aggregationBuilder = new FilterAggregationBuilder("_name1", QueryBuilders.termQuery("include", "yes"));
|
||||
aggregationBuilder.subAggregation(new TermsAggregationBuilder("_name2", valueType)
|
||||
.executionHint(executionHint)
|
||||
.size(numTerms)
|
||||
.collectMode(randomFrom(Aggregator.SubAggCollectionMode.values()))
|
||||
.field("field"));
|
||||
aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType);
|
||||
aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType, filterFieldType);
|
||||
aggregator.preCollection();
|
||||
indexSearcher.search(new MatchAllDocsQuery(), aggregator);
|
||||
aggregator.postCollection();
|
||||
|
|
|
@ -291,6 +291,7 @@ public class HighlightBuilderTests extends ESTestCase {
|
|||
|
||||
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
||||
HighlightBuilder highlightBuilder = randomHighlighterBuilder();
|
||||
highlightBuilder = Rewriteable.rewrite(highlightBuilder, mockShardContext);
|
||||
SearchContextHighlight highlight = highlightBuilder.build(mockShardContext);
|
||||
for (SearchContextHighlight.Field field : highlight.fields()) {
|
||||
String encoder = highlightBuilder.encoder() != null ? highlightBuilder.encoder() : HighlightBuilder.DEFAULT_ENCODER;
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.elasticsearch.index.query.IdsQueryBuilder;
|
|||
import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.Rewriteable;
|
||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||
import org.elasticsearch.script.MockScriptEngine;
|
||||
import org.elasticsearch.script.ScriptEngine;
|
||||
|
@ -154,7 +155,8 @@ public abstract class AbstractSortTestCase<T extends SortBuilder<T>> extends EST
|
|||
QueryShardContext mockShardContext = createMockShardContext();
|
||||
for (int runs = 0; runs < NUMBER_OF_TESTBUILDERS; runs++) {
|
||||
T sortBuilder = createTestItem();
|
||||
SortFieldAndFormat sortField = sortBuilder.build(mockShardContext);
|
||||
SortFieldAndFormat sortField = Rewriteable.rewrite(sortBuilder, mockShardContext)
|
||||
.build(mockShardContext);
|
||||
sortFieldAssertions(sortBuilder, sortField.field, sortField.format);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,7 +166,9 @@ public abstract class AggregatorTestCase extends ESTestCase {
|
|||
MappedFieldType... fieldTypes) throws IOException {
|
||||
SearchContext searchContext = createSearchContext(indexSearcher, indexSettings, query, bucketConsumer, fieldTypes);
|
||||
@SuppressWarnings("unchecked")
|
||||
A aggregator = (A) aggregationBuilder.build(searchContext.getQueryShardContext(), null)
|
||||
A aggregator = (A) aggregationBuilder
|
||||
.rewrite(searchContext.getQueryShardContext())
|
||||
.build(searchContext.getQueryShardContext(), null)
|
||||
.create(searchContext, null, true);
|
||||
return aggregator;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.test;
|
|||
import com.fasterxml.jackson.core.io.JsonStringEncoder;
|
||||
|
||||
import org.apache.lucene.search.BoostQuery;
|
||||
import org.apache.lucene.search.MatchNoDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.spans.SpanBoostQuery;
|
||||
|
@ -453,7 +454,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
|||
rewrite(secondLuceneQuery), rewrite(firstLuceneQuery));
|
||||
}
|
||||
|
||||
if (supportsBoost()) {
|
||||
if (supportsBoost() && firstLuceneQuery instanceof MatchNoDocsQuery == false) {
|
||||
secondQuery.boost(firstQuery.boost() + 1f + randomFloat());
|
||||
Query thirdLuceneQuery = rewriteQuery(secondQuery, context).toQuery(context);
|
||||
assertNotEquals("modifying the boost doesn't affect the corresponding lucene query", rewrite(firstLuceneQuery),
|
||||
|
@ -495,20 +496,23 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
|||
* {@link #doAssertLuceneQuery(AbstractQueryBuilder, Query, QueryShardContext)} for query specific checks.
|
||||
*/
|
||||
private void assertLuceneQuery(QB queryBuilder, Query query, QueryShardContext context) throws IOException {
|
||||
if (queryBuilder.queryName() != null) {
|
||||
if (queryBuilder.queryName() != null && query instanceof MatchNoDocsQuery == false) {
|
||||
Query namedQuery = context.copyNamedQueries().get(queryBuilder.queryName());
|
||||
assertThat(namedQuery, equalTo(query));
|
||||
}
|
||||
if (query != null) {
|
||||
if (queryBuilder.boost() != AbstractQueryBuilder.DEFAULT_BOOST) {
|
||||
assertThat(query, either(instanceOf(BoostQuery.class)).or(instanceOf(SpanBoostQuery.class)));
|
||||
assertThat(query, either(instanceOf(BoostQuery.class)).or(instanceOf(SpanBoostQuery.class))
|
||||
.or(instanceOf(MatchNoDocsQuery.class)));
|
||||
if (query instanceof SpanBoostQuery) {
|
||||
SpanBoostQuery spanBoostQuery = (SpanBoostQuery) query;
|
||||
assertThat(spanBoostQuery.getBoost(), equalTo(queryBuilder.boost()));
|
||||
query = spanBoostQuery.getQuery();
|
||||
} else {
|
||||
} else if (query instanceof BoostQuery) {
|
||||
BoostQuery boostQuery = (BoostQuery) query;
|
||||
assertThat(boostQuery.getBoost(), equalTo(queryBuilder.boost()));
|
||||
if (boostQuery.getQuery() instanceof MatchNoDocsQuery == false) {
|
||||
assertThat(boostQuery.getBoost(), equalTo(queryBuilder.boost()));
|
||||
}
|
||||
query = boostQuery.getQuery();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.elasticsearch.common.logging.Loggers;
|
|||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.index.IndexSettings;
|
||||
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
|
@ -68,6 +69,7 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
public class DocumentSubsetBitsetCacheTests extends ESTestCase {
|
||||
|
||||
private static final String MISSING_FIELD_NAME = "does-not-exist";
|
||||
private static final int FIELD_COUNT = 10;
|
||||
private ExecutorService singleThreadExecutor;
|
||||
|
||||
|
@ -99,7 +101,7 @@ public class DocumentSubsetBitsetCacheTests extends ESTestCase {
|
|||
public void testNullBitSetIsReturnedForNonMatchingQuery() throws Exception {
|
||||
final DocumentSubsetBitsetCache cache = newCache(Settings.EMPTY);
|
||||
runTestOnIndex((shardContext, leafContext) -> {
|
||||
final Query query = QueryBuilders.termQuery("does-not-exist", "any-value").toQuery(shardContext);
|
||||
final Query query = QueryBuilders.termQuery(MISSING_FIELD_NAME, "any-value").rewrite(shardContext).toQuery(shardContext);
|
||||
final BitSet bitSet = cache.getBitSet(query, leafContext);
|
||||
assertThat(bitSet, nullValue());
|
||||
});
|
||||
|
@ -543,6 +545,17 @@ public class DocumentSubsetBitsetCacheTests extends ESTestCase {
|
|||
|
||||
private void runTestOnIndices(int numberIndices, CheckedConsumer<List<TestIndexContext>, Exception> body) throws Exception {
|
||||
final MapperService mapperService = mock(MapperService.class);
|
||||
when(mapperService.fieldType(Mockito.anyString())).thenAnswer(invocation -> {
|
||||
final String fieldName = (String) invocation.getArguments()[0];
|
||||
if (fieldName.equals(MISSING_FIELD_NAME)) {
|
||||
return null;
|
||||
} else {
|
||||
KeywordFieldMapper.KeywordFieldType ft = new KeywordFieldMapper.KeywordFieldType();
|
||||
ft.setName(fieldName);
|
||||
ft.freeze();
|
||||
return ft;
|
||||
}
|
||||
});
|
||||
|
||||
final Client client = mock(Client.class);
|
||||
when(client.settings()).thenReturn(Settings.EMPTY);
|
||||
|
|
|
@ -29,12 +29,14 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
import org.elasticsearch.index.IndexSettings;
|
||||
import org.elasticsearch.index.mapper.KeywordFieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.query.ParsedQuery;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.TermsQueryBuilder;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.mock.orig.Mockito;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.internal.ContextIndexSearcher;
|
||||
import org.elasticsearch.test.AbstractBuilderTestCase;
|
||||
|
@ -69,6 +71,13 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
|||
when(mapperService.documentMapper()).thenReturn(null);
|
||||
when(mapperService.simpleMatchToFullName(anyString()))
|
||||
.then(invocationOnMock -> Collections.singletonList((String) invocationOnMock.getArguments()[0]));
|
||||
when(mapperService.fieldType(Mockito.anyString())).then(invocation -> {
|
||||
final String fieldName = (String) invocation.getArguments()[0];
|
||||
KeywordFieldMapper.KeywordFieldType ft = new KeywordFieldMapper.KeywordFieldType();
|
||||
ft.setName(fieldName);
|
||||
ft.freeze();
|
||||
return ft;
|
||||
});
|
||||
|
||||
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
|
@ -177,6 +186,13 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
|||
when(mapperService.documentMapper()).thenReturn(null);
|
||||
when(mapperService.simpleMatchToFullName(anyString()))
|
||||
.then(invocationOnMock -> Collections.singletonList((String) invocationOnMock.getArguments()[0]));
|
||||
when(mapperService.fieldType(Mockito.anyString())).then(invocation -> {
|
||||
final String fieldName = (String) invocation.getArguments()[0];
|
||||
KeywordFieldMapper.KeywordFieldType ft = new KeywordFieldMapper.KeywordFieldType();
|
||||
ft.setName(fieldName);
|
||||
ft.freeze();
|
||||
return ft;
|
||||
});
|
||||
|
||||
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||
final SecurityContext securityContext = new SecurityContext(Settings.EMPTY, threadContext);
|
||||
|
@ -203,7 +219,8 @@ public class SecurityIndexReaderWrapperIntegrationTests extends AbstractBuilderT
|
|||
IndicesAccessControl.IndexAccessControl limitedIndexAccessControl = new IndicesAccessControl.IndexAccessControl(true, new
|
||||
FieldPermissions(),
|
||||
DocumentPermissions.filteredBy(queries));
|
||||
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.getIndex(), Settings.EMPTY);
|
||||
IndexSettings indexSettings = IndexSettingsModule.newIndexSettings(shardId.getIndex(),
|
||||
Settings.builder().put(IndexSettings.ALLOW_UNMAPPED.getKey(), false).build());
|
||||
Client client = mock(Client.class);
|
||||
when(client.settings()).thenReturn(Settings.EMPTY);
|
||||
final long nowInMillis = randomNonNegativeLong();
|
||||
|
|
|
@ -170,4 +170,13 @@ public class PinnedQueryBuilderTests extends AbstractQueryTestCase<PinnedQueryBu
|
|||
assertThat(rewritten, instanceOf(PinnedQueryBuilder.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
QueryShardContext context = createShardContext();
|
||||
context.setAllowUnmappedFields(true);
|
||||
PinnedQueryBuilder queryBuilder = new PinnedQueryBuilder(new TermQueryBuilder("unmapped_field", "42"));
|
||||
IllegalStateException e = expectThrows(IllegalStateException.class,
|
||||
() -> queryBuilder.toQuery(context));
|
||||
assertEquals("Rewrite first", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue