diff options
author | Christoph Büscher <christoph@elastic.co> | 2016-04-20 13:19:12 +0200 |
---|---|---|
committer | Christoph Büscher <christoph@elastic.co> | 2016-06-02 11:25:56 +0200 |
commit | 359f45988fa5550ff44a0f805fa050eb9a221405 (patch) | |
tree | 6facefbd87f2ed55d9f2142b7896d6f65796bf05 | |
parent | b2724c0d08267486efc261a30bdb686cb9977f5d (diff) |
Handle empty query bodies at parse time and remove EmptyQueryBuilder
Currently we support empty query clauses like the filter in
"constant_score" : { "filter" : { } }
How these clauses are handled depends on the surrounding query.
They later are either ignored, converted to match all or no documents or
passed up further in the query hierarchy. During parsing these claues are
currently represented as EmptyQueryBuilders. When not handled anywhere else,
these special cases need to be checked for on the shard when building the
lucene query.
This is trappy, so this PR changes the parsing of compound queries. Instead
of returning QueryBuilder, the core query parsing method
QueryShardContext#parseInnerQueryBuilder() now return an Optional which can
be empty in the case of empty query clauses. This has the advantage of forcing
callers to deal with this sooner or later. When encountering empty Optionals,
compound query builders now have the choice to ignore them, pass them on or
rewrite to a different query, depending on context.
87 files changed, 640 insertions, 431 deletions
diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/AliasValidator.java b/core/src/main/java/org/elasticsearch/cluster/metadata/AliasValidator.java index 735916504d..647e30cd85 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/AliasValidator.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/AliasValidator.java @@ -32,6 +32,7 @@ import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.indices.InvalidAliasNameException; import java.io.IOException; +import java.util.Optional; /** * Validator for an alias, to be used before adding an alias to the index metadata @@ -141,7 +142,10 @@ public class AliasValidator extends AbstractComponent { private static void validateAliasFilter(XContentParser parser, QueryShardContext queryShardContext) throws IOException { QueryParseContext queryParseContext = queryShardContext.newParseContext(parser); - QueryBuilder queryBuilder = QueryBuilder.rewriteQuery(queryParseContext.parseInnerQueryBuilder(), queryShardContext); - queryBuilder.toFilter(queryShardContext); + Optional<QueryBuilder> parseInnerQueryBuilder = queryParseContext.parseInnerQueryBuilder(); + if (parseInnerQueryBuilder.isPresent()) { + QueryBuilder queryBuilder = QueryBuilder.rewriteQuery(parseInnerQueryBuilder.get(), queryShardContext); + queryBuilder.toFilter(queryShardContext); + } } } diff --git a/core/src/main/java/org/elasticsearch/index/IndexService.java b/core/src/main/java/org/elasticsearch/index/IndexService.java index f5e5ce91d8..e2d2ea4b8f 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexService.java +++ b/core/src/main/java/org/elasticsearch/index/IndexService.java @@ -51,6 +51,7 @@ import org.elasticsearch.index.fielddata.IndexFieldDataCache; import org.elasticsearch.index.fielddata.IndexFieldDataService; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.query.ParsedQuery; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.shard.IndexEventListener; import org.elasticsearch.index.shard.IndexSearcherWrapper; @@ -80,6 +81,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -601,7 +603,11 @@ public final class IndexService extends AbstractIndexComponent implements IndexC try { byte[] filterSource = alias.filter().uncompressed(); try (XContentParser parser = XContentFactory.xContent(filterSource).createParser(filterSource)) { - ParsedQuery parsedFilter = shardContext.toFilter(shardContext.newParseContext(parser).parseInnerQueryBuilder()); + Optional<QueryBuilder> innerQueryBuilder = shardContext.newParseContext(parser).parseInnerQueryBuilder(); + ParsedQuery parsedFilter = null; + if (innerQueryBuilder.isPresent()) { + parsedFilter = shardContext.toFilter(innerQueryBuilder.get()); + } return parsedFilter == null ? null : parsedFilter.query(); } } catch (IOException ex) { diff --git a/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java index e5aa774add..863bdb25c7 100644 --- a/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/BoolQueryBuilder.java @@ -37,6 +37,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Consumer; import static org.elasticsearch.common.lucene.search.Queries.fixNegativeQueryIfNeeded; @@ -300,7 +301,7 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> { builder.endArray(); } - public static BoolQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { + public static Optional<BoolQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { XContentParser parser = parseContext.parser(); boolean disableCoord = BoolQueryBuilder.DISABLE_COORD_DEFAULT; @@ -316,7 +317,6 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> { String currentFieldName = null; XContentParser.Token token; - QueryBuilder query; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); @@ -325,21 +325,17 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> { } else if (token == XContentParser.Token.START_OBJECT) { switch (currentFieldName) { case MUST: - query = parseContext.parseInnerQueryBuilder(); - mustClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(mustClauses::add); break; case SHOULD: - query = parseContext.parseInnerQueryBuilder(); - shouldClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(shouldClauses::add); break; case FILTER: - query = parseContext.parseInnerQueryBuilder(); - filterClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(filterClauses::add); break; case MUST_NOT: case MUSTNOT: - query = parseContext.parseInnerQueryBuilder(); - mustNotClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(mustNotClauses::add); break; default: throw new ParsingException(parser.getTokenLocation(), "[bool] query does not support [" + currentFieldName + "]"); @@ -348,21 +344,17 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { switch (currentFieldName) { case MUST: - query = parseContext.parseInnerQueryBuilder(); - mustClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(mustClauses::add); break; case SHOULD: - query = parseContext.parseInnerQueryBuilder(); - shouldClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(shouldClauses::add); break; case FILTER: - query = parseContext.parseInnerQueryBuilder(); - filterClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(filterClauses::add); break; case MUST_NOT: case MUSTNOT: - query = parseContext.parseInnerQueryBuilder(); - mustNotClauses.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(mustNotClauses::add); break; default: throw new ParsingException(parser.getTokenLocation(), "bool query does not support [" + currentFieldName + "]"); @@ -404,7 +396,7 @@ public class BoolQueryBuilder extends AbstractQueryBuilder<BoolQueryBuilder> { boolQuery.adjustPureNegative(adjustPureNegative); boolQuery.minimumNumberShouldMatch(minimumShouldMatch); boolQuery.queryName(queryName); - return boolQuery; + return Optional.of(boolQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/BoostingQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/BoostingQueryBuilder.java index 496cb7ec8a..3afa4339b5 100644 --- a/core/src/main/java/org/elasticsearch/index/query/BoostingQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/BoostingQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * The BoostingQuery class can be used to effectively demote results that match a given query. @@ -138,12 +139,12 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil builder.endObject(); } - public static BoostingQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<BoostingQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); - QueryBuilder positiveQuery = null; + Optional<QueryBuilder> positiveQuery = null; boolean positiveQueryFound = false; - QueryBuilder negativeQuery = null; + Optional<QueryBuilder> negativeQuery = null; boolean negativeQueryFound = false; float boost = AbstractQueryBuilder.DEFAULT_BOOST; float negativeBoost = -1; @@ -187,12 +188,15 @@ public class BoostingQueryBuilder extends AbstractQueryBuilder<BoostingQueryBuil throw new ParsingException(parser.getTokenLocation(), "[boosting] query requires 'negative_boost' to be set to be a positive value'"); } + if (positiveQuery.isPresent() == false || negativeQuery.isPresent() == false) { + return Optional.empty(); + } - BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery, negativeQuery); + BoostingQueryBuilder boostingQuery = new BoostingQueryBuilder(positiveQuery.get(), negativeQuery.get()); boostingQuery.negativeBoost(negativeBoost); boostingQuery.boost(boost); boostingQuery.queryName(queryName); - return boostingQuery; + return Optional.of(boostingQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/CommonTermsQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/CommonTermsQueryBuilder.java index f7b35d8dfa..692c157c1b 100644 --- a/core/src/main/java/org/elasticsearch/index/query/CommonTermsQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/CommonTermsQueryBuilder.java @@ -40,6 +40,7 @@ import org.elasticsearch.index.mapper.MappedFieldType; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * CommonTermsQuery query is a query that executes high-frequency terms in a @@ -263,7 +264,7 @@ public class CommonTermsQueryBuilder extends AbstractQueryBuilder<CommonTermsQue builder.endObject(); } - public static CommonTermsQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<CommonTermsQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); if (token != XContentParser.Token.FIELD_NAME) { @@ -352,7 +353,7 @@ public class CommonTermsQueryBuilder extends AbstractQueryBuilder<CommonTermsQue if (text == null) { throw new ParsingException(parser.getTokenLocation(), "No text specified for text query"); } - return new CommonTermsQueryBuilder(fieldName, text) + return Optional.of(new CommonTermsQueryBuilder(fieldName, text) .lowFreqMinimumShouldMatch(lowFreqMinimumShouldMatch) .highFreqMinimumShouldMatch(highFreqMinimumShouldMatch) .analyzer(analyzer) @@ -361,7 +362,7 @@ public class CommonTermsQueryBuilder extends AbstractQueryBuilder<CommonTermsQue .disableCoord(disableCoord) .cutoffFrequency(cutoffFrequency) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/ConstantScoreQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ConstantScoreQueryBuilder.java index 306a456857..44b4458b57 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ConstantScoreQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ConstantScoreQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * A query that wraps a filter and simply returns a constant score equal to the @@ -87,10 +88,10 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor builder.endObject(); } - public static ConstantScoreQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<ConstantScoreQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); - QueryBuilder query = null; + Optional<QueryBuilder> query = Optional.empty(); boolean queryFound = false; String queryName = null; float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -131,10 +132,15 @@ public class ConstantScoreQueryBuilder extends AbstractQueryBuilder<ConstantScor throw new ParsingException(parser.getTokenLocation(), "[constant_score] requires a 'filter' element"); } - ConstantScoreQueryBuilder constantScoreBuilder = new ConstantScoreQueryBuilder(query); + if (query.isPresent() == false) { + // if inner query is empty, bubble this up to caller so they can decide how to deal with it + return Optional.empty(); + } + + ConstantScoreQueryBuilder constantScoreBuilder = new ConstantScoreQueryBuilder(query.get()); constantScoreBuilder.boost(boost); constantScoreBuilder.queryName(queryName); - return constantScoreBuilder; + return Optional.of(constantScoreBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/DisMaxQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/DisMaxQueryBuilder.java index f38b2c09b1..e480417e8f 100644 --- a/core/src/main/java/org/elasticsearch/index/query/DisMaxQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/DisMaxQueryBuilder.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * A query that generates the union of documents produced by its sub-queries, and that scores each document @@ -122,7 +123,7 @@ public class DisMaxQueryBuilder extends AbstractQueryBuilder<DisMaxQueryBuilder> builder.endObject(); } - public static DisMaxQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<DisMaxQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -140,8 +141,7 @@ public class DisMaxQueryBuilder extends AbstractQueryBuilder<DisMaxQueryBuilder> } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERIES_FIELD)) { queriesFound = true; - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - queries.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(queries::add); } else { throw new ParsingException(parser.getTokenLocation(), "[dis_max] query does not support [" + currentFieldName + "]"); } @@ -149,8 +149,7 @@ public class DisMaxQueryBuilder extends AbstractQueryBuilder<DisMaxQueryBuilder> if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERIES_FIELD)) { queriesFound = true; while (token != XContentParser.Token.END_ARRAY) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - queries.add(query); + parseContext.parseInnerQueryBuilder().ifPresent(queries::add); token = parser.nextToken(); } } else { @@ -180,7 +179,7 @@ public class DisMaxQueryBuilder extends AbstractQueryBuilder<DisMaxQueryBuilder> for (QueryBuilder query : queries) { disMaxQuery.add(query); } - return disMaxQuery; + return Optional.of(disMaxQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java index afcff164be..c933bae68c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ExistsQueryBuilder.java @@ -37,6 +37,7 @@ import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Objects; +import java.util.Optional; /** * Constructs a query that only match on documents that the field has a value in them. @@ -85,7 +86,7 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder> builder.endObject(); } - public static ExistsQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<ExistsQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldPattern = null; @@ -121,7 +122,7 @@ public class ExistsQueryBuilder extends AbstractQueryBuilder<ExistsQueryBuilder> ExistsQueryBuilder builder = new ExistsQueryBuilder(fieldPattern); builder.queryName(queryName); builder.boost(boost); - return builder; + return Optional.of(builder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/FieldMaskingSpanQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/FieldMaskingSpanQueryBuilder.java index 0382f353cb..801b0ae5a8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/FieldMaskingSpanQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/FieldMaskingSpanQueryBuilder.java @@ -33,6 +33,7 @@ import org.elasticsearch.index.mapper.MappedFieldType; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMaskingSpanQueryBuilder> implements SpanQueryBuilder { @@ -103,7 +104,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask builder.endObject(); } - public static FieldMaskingSpanQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<FieldMaskingSpanQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -119,11 +120,11 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "[field_masking_span] query must be of type span query"); } - inner = (SpanQueryBuilder) query; + inner = (SpanQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[field_masking_span] query does not support [" + currentFieldName + "]"); @@ -151,7 +152,7 @@ public class FieldMaskingSpanQueryBuilder extends AbstractQueryBuilder<FieldMask FieldMaskingSpanQueryBuilder queryBuilder = new FieldMaskingSpanQueryBuilder(inner, field); queryBuilder.boost(boost); queryBuilder.queryName(queryName); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java index 70b4f5eb7f..6e60c19d2f 100644 --- a/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/FuzzyQueryBuilder.java @@ -37,6 +37,7 @@ import org.elasticsearch.index.query.support.QueryParsers; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * A Query that does fuzzy matching for a specific value. @@ -257,7 +258,7 @@ public class FuzzyQueryBuilder extends AbstractQueryBuilder<FuzzyQueryBuilder> i builder.endObject(); } - public static FuzzyQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<FuzzyQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -317,14 +318,14 @@ public class FuzzyQueryBuilder extends AbstractQueryBuilder<FuzzyQueryBuilder> i if (value == null) { throw new ParsingException(parser.getTokenLocation(), "no value specified for fuzzy query"); } - return new FuzzyQueryBuilder(fieldName, value) + return Optional.of(new FuzzyQueryBuilder(fieldName, value) .fuzziness(fuzziness) .prefixLength(prefixLength) .maxExpansions(maxExpansions) .transpositions(transpositions) .rewrite(rewrite) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java index 7f5d5e2ec8..c1925fe3f3 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoBoundingBoxQueryBuilder.java @@ -43,6 +43,7 @@ import org.elasticsearch.index.search.geo.IndexedGeoBoundingBoxQuery; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Creates a Lucene query that will filter for all documents that lie within the specified @@ -385,7 +386,7 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding builder.endObject(); } - public static GeoBoundingBoxQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<GeoBoundingBoxQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -496,7 +497,7 @@ public class GeoBoundingBoxQueryBuilder extends AbstractQueryBuilder<GeoBounding } else { builder.setValidationMethod(GeoValidationMethod.infer(coerce, ignoreMalformed)); } - return builder; + return Optional.of(builder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java index 0f2b4694e2..710cb529c0 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoDistanceQueryBuilder.java @@ -45,6 +45,7 @@ import org.elasticsearch.index.search.geo.GeoDistanceRangeQuery; import java.io.IOException; import java.util.Locale; import java.util.Objects; +import java.util.Optional; /** * Filter results of a query to include only those within a specific distance to some @@ -330,7 +331,7 @@ public class GeoDistanceQueryBuilder extends AbstractQueryBuilder<GeoDistanceQue builder.endObject(); } - public static GeoDistanceQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<GeoDistanceQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token; @@ -445,7 +446,7 @@ public class GeoDistanceQueryBuilder extends AbstractQueryBuilder<GeoDistanceQue qb.boost(boost); qb.queryName(queryName); qb.ignoreUnmapped(ignoreUnmapped); - return qb; + return Optional.of(qb); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoDistanceRangeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoDistanceRangeQueryBuilder.java index ea22461243..06f30a3477 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoDistanceRangeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoDistanceRangeQueryBuilder.java @@ -46,6 +46,7 @@ import org.elasticsearch.index.search.geo.GeoDistanceRangeQuery; import java.io.IOException; import java.util.Locale; import java.util.Objects; +import java.util.Optional; import static org.apache.lucene.spatial.util.GeoEncodingUtils.TOLERANCE; @@ -391,7 +392,7 @@ public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistan builder.endObject(); } - public static GeoDistanceRangeQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<GeoDistanceRangeQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token; @@ -603,7 +604,7 @@ public class GeoDistanceRangeQueryBuilder extends AbstractQueryBuilder<GeoDistan queryBuilder.setValidationMethod(GeoValidationMethod.infer(coerce, ignoreMalformed)); } queryBuilder.ignoreUnmapped(ignoreUnmapped); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java index 35ab98e25d..97c9990a9f 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoPolygonQueryBuilder.java @@ -43,6 +43,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; public class GeoPolygonQueryBuilder extends AbstractQueryBuilder<GeoPolygonQueryBuilder> { @@ -241,7 +242,7 @@ public class GeoPolygonQueryBuilder extends AbstractQueryBuilder<GeoPolygonQuery builder.endObject(); } - public static GeoPolygonQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<GeoPolygonQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -322,7 +323,7 @@ public class GeoPolygonQueryBuilder extends AbstractQueryBuilder<GeoPolygonQuery builder.boost(boost); } builder.ignoreUnmapped(ignoreUnmapped); - return builder; + return Optional.of(builder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java index 8b3c8a6248..0b04629e2c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeoShapeQueryBuilder.java @@ -47,6 +47,7 @@ import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * {@link QueryBuilder} that builds a GeoShape Query @@ -453,7 +454,7 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil builder.endObject(); } - public static GeoShapeQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<GeoShapeQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -559,7 +560,7 @@ public class GeoShapeQueryBuilder extends AbstractQueryBuilder<GeoShapeQueryBuil } builder.boost(boost); builder.ignoreUnmapped(ignoreUnmapped); - return builder; + return Optional.of(builder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/GeohashCellQuery.java b/core/src/main/java/org/elasticsearch/index/query/GeohashCellQuery.java index 4f34d6db31..f9f21bac7b 100644 --- a/core/src/main/java/org/elasticsearch/index/query/GeohashCellQuery.java +++ b/core/src/main/java/org/elasticsearch/index/query/GeohashCellQuery.java @@ -21,12 +21,12 @@ package org.elasticsearch.index.query; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; -import org.elasticsearch.common.geo.GeoHashUtils; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.geo.GeoHashUtils; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.geo.GeoUtils; import org.elasticsearch.common.io.stream.StreamInput; @@ -42,6 +42,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * A geohash cell filter that filters {@link GeoPoint}s by their geohashes. Basically the a @@ -280,7 +281,7 @@ public class GeohashCellQuery { builder.endObject(); } - public static Builder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<Builder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -362,7 +363,7 @@ public class GeohashCellQuery { builder.boost(boost); } builder.ignoreUnmapped(ignoreUnmapped); - return builder; + return Optional.of(builder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java index 990b5a35fd..410fda41ae 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java @@ -43,6 +43,7 @@ import java.io.IOException; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * A query builder for <tt>has_child</tt> query. @@ -226,7 +227,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil builder.endObject(); } - public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<HasChildQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; String childType = null; @@ -238,7 +239,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil InnerHitBuilder innerHitBuilder = null; String currentFieldName = null; XContentParser.Token token; - QueryBuilder iqb = null; + Optional<QueryBuilder> iqb = Optional.empty(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); @@ -272,7 +273,13 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil } } } - HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder(childType, iqb, scoreMode); + + if (iqb.isPresent() == false) { + // if inner query is empty, bubble this up to caller so they can decide how to deal with it + return Optional.empty(); + } + + HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder(childType, iqb.get(), scoreMode); if (innerHitBuilder != null) { hasChildQueryBuilder.innerHit(innerHitBuilder); } @@ -280,7 +287,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil hasChildQueryBuilder.queryName(queryName); hasChildQueryBuilder.boost(boost); hasChildQueryBuilder.ignoreUnmapped(ignoreUnmapped); - return hasChildQueryBuilder; + return Optional.of(hasChildQueryBuilder); } public static ScoreMode parseScoreMode(String scoreModeString) { diff --git a/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java index 96356c276e..7e788a16e8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java @@ -38,6 +38,7 @@ import java.io.IOException; import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; /** @@ -227,7 +228,7 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu builder.endObject(); } - public static HasParentQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<HasParentQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; String parentType = null; @@ -238,7 +239,7 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu String currentFieldName = null; XContentParser.Token token; - QueryBuilder iqb = null; + Optional<QueryBuilder> iqb = Optional.empty(); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); @@ -276,14 +277,18 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu } } } - HasParentQueryBuilder queryBuilder = new HasParentQueryBuilder(parentType, iqb, score) + if (iqb.isPresent() == false) { + // if inner query is empty, bubble this up to caller so they can decide how to deal with it + return Optional.empty(); + } + HasParentQueryBuilder queryBuilder = new HasParentQueryBuilder(parentType, iqb.get(), score) .ignoreUnmapped(ignoreUnmapped) .queryName(queryName) .boost(boost); if (innerHits != null) { queryBuilder.innerHit(innerHits); } - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/IdsQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/IdsQueryBuilder.java index 7845e2732e..d2c847c55c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/IdsQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/IdsQueryBuilder.java @@ -40,6 +40,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; /** @@ -127,7 +128,7 @@ public class IdsQueryBuilder extends AbstractQueryBuilder<IdsQueryBuilder> { builder.endObject(); } - public static IdsQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<IdsQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); List<String> ids = new ArrayList<>(); List<String> types = new ArrayList<>(); @@ -191,7 +192,7 @@ public class IdsQueryBuilder extends AbstractQueryBuilder<IdsQueryBuilder> { IdsQueryBuilder query = new IdsQueryBuilder(types.toArray(new String[types.size()])); query.addIds(ids.toArray(new String[ids.size()])); query.boost(boost).queryName(queryName); - return query; + return Optional.of(query); } diff --git a/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java index 7cfdf1baa1..9758ad3f54 100644 --- a/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/IndicesQueryBuilder.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Objects; +import java.util.Optional; /** * A query that will execute the wrapped query only for the specified indices, @@ -141,7 +142,7 @@ public class IndicesQueryBuilder extends AbstractQueryBuilder<IndicesQueryBuilde builder.endObject(); } - public static IndicesQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { + public static Optional<IndicesQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { XContentParser parser = parseContext.parser(); QueryBuilder innerQuery = null; @@ -158,9 +159,10 @@ public class IndicesQueryBuilder extends AbstractQueryBuilder<IndicesQueryBuilde currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) { - innerQuery = parseContext.parseInnerQueryBuilder(); + // the 2.0 behaviour when encountering "query" : {} is to return no docs for matching indices + innerQuery = parseContext.parseInnerQueryBuilder().orElse(new MatchNoneQueryBuilder()); } else if (parseContext.getParseFieldMatcher().match(currentFieldName, NO_MATCH_QUERY)) { - noMatchQuery = parseContext.parseInnerQueryBuilder(); + noMatchQuery = parseContext.parseInnerQueryBuilder().orElse(defaultNoMatchQuery()); } else { throw new ParsingException(parser.getTokenLocation(), "[indices] query does not support [" + currentFieldName + "]"); } @@ -203,10 +205,10 @@ public class IndicesQueryBuilder extends AbstractQueryBuilder<IndicesQueryBuilde if (indices.isEmpty()) { throw new ParsingException(parser.getTokenLocation(), "[indices] requires 'indices' or 'index' element"); } - return new IndicesQueryBuilder(innerQuery, indices.toArray(new String[indices.size()])) + return Optional.of(new IndicesQueryBuilder(innerQuery, indices.toArray(new String[indices.size()])) .noMatchQuery(noMatchQuery) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } static QueryBuilder parseNoMatchQuery(String type) { diff --git a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java index b62b5a18a1..a017159b45 100644 --- a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java @@ -60,6 +60,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl public static final ParseField NAME_FIELD = new ParseField("name"); public static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits"); + public static final QueryBuilder DEFAULT_INNER_HIT_QUERY = new MatchAllQueryBuilder(); private final static ObjectParser<InnerHitBuilder, QueryParseContext> PARSER = new ObjectParser<>("inner_hits", InnerHitBuilder::new); @@ -131,7 +132,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl private boolean trackScores; private List<String> fieldNames; - private QueryBuilder query = new MatchAllQueryBuilder(); + private QueryBuilder query = DEFAULT_INNER_HIT_QUERY; private List<SortBuilder<?>> sorts; private List<String> fieldDataFields; private Set<ScriptField> scriptFields; @@ -394,7 +395,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl return this; } - public InnerHitBuilder addSort(SortBuilder sort) { + public InnerHitBuilder addSort(SortBuilder<?> sort) { if (sorts == null) { sorts = new ArrayList<>(); } diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchAllQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchAllQueryBuilder.java index 2d415c2b2a..21742eb877 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchAllQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchAllQueryBuilder.java @@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Optional; /** * A query that matches on all documents. @@ -60,7 +61,7 @@ public class MatchAllQueryBuilder extends AbstractQueryBuilder<MatchAllQueryBuil builder.endObject(); } - public static MatchAllQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MatchAllQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String currentFieldName = null; @@ -87,7 +88,7 @@ public class MatchAllQueryBuilder extends AbstractQueryBuilder<MatchAllQueryBuil MatchAllQueryBuilder queryBuilder = new MatchAllQueryBuilder(); queryBuilder.boost(boost); queryBuilder.queryName(queryName); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchNoneQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchNoneQueryBuilder.java index 068b0e86d8..f96c6160ee 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchNoneQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchNoneQueryBuilder.java @@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Optional; /** * A query that matches no document. @@ -60,7 +61,7 @@ public class MatchNoneQueryBuilder extends AbstractQueryBuilder<MatchNoneQueryBu builder.endObject(); } - public static MatchNoneQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MatchNoneQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String currentFieldName = null; @@ -88,7 +89,7 @@ public class MatchNoneQueryBuilder extends AbstractQueryBuilder<MatchNoneQueryBu MatchNoneQueryBuilder matchNoneQueryBuilder = new MatchNoneQueryBuilder(); matchNoneQueryBuilder.boost(boost); matchNoneQueryBuilder.queryName(queryName); - return matchNoneQueryBuilder; + return Optional.of(matchNoneQueryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java index cb20d448f8..002b5e2343 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.index.search.MatchQuery; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Match query is a query that analyzes the text and constructs a phrase prefix @@ -191,7 +192,7 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr return Objects.hash(fieldName, value, analyzer, slop, maxExpansions); } - public static MatchPhrasePrefixQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MatchPhrasePrefixQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -257,6 +258,6 @@ public class MatchPhrasePrefixQueryBuilder extends AbstractQueryBuilder<MatchPhr matchQuery.maxExpansions(maxExpansion); matchQuery.queryName(queryName); matchQuery.boost(boost); - return matchQuery; + return Optional.of(matchQuery); } } diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java index 7fef776bbc..2621c2dc50 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java @@ -27,8 +27,10 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.search.MatchQuery; + import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Match query is a query that analyzes the text and constructs a phrase query @@ -161,7 +163,7 @@ public class MatchPhraseQueryBuilder extends AbstractQueryBuilder<MatchPhraseQue return Objects.hash(fieldName, value, analyzer, slop); } - public static MatchPhraseQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MatchPhraseQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -223,6 +225,6 @@ public class MatchPhraseQueryBuilder extends AbstractQueryBuilder<MatchPhraseQue matchQuery.slop(slop); matchQuery.queryName(queryName); matchQuery.boost(boost); - return matchQuery; + return Optional.of(matchQuery); } } diff --git a/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java index 6c86759065..04fa9120a7 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MatchQueryBuilder.java @@ -38,6 +38,7 @@ import org.elasticsearch.index.search.MatchQuery.ZeroTermsQuery; import java.io.IOException; import java.util.Locale; import java.util.Objects; +import java.util.Optional; /** * Match query is a query that analyzes the text and constructs a query as the @@ -507,7 +508,7 @@ public class MatchQueryBuilder extends AbstractQueryBuilder<MatchQueryBuilder> { return NAME; } - public static MatchQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MatchQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -633,7 +634,7 @@ public class MatchQueryBuilder extends AbstractQueryBuilder<MatchQueryBuilder> { matchQuery.zeroTermsQuery(zeroTermsQuery); matchQuery.queryName(queryName); matchQuery.boost(boost); - return matchQuery; + return Optional.of(matchQuery); } } diff --git a/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java index 66f623cbbb..5fa36ec977 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java @@ -805,7 +805,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ builder.endObject(); } - public static MoreLikeThisQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MoreLikeThisQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); // document inputs @@ -955,7 +955,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ if (stopWords != null) { moreLikeThisQueryBuilder.stopWords(stopWords); } - return moreLikeThisQueryBuilder; + return Optional.of(moreLikeThisQueryBuilder); } private static void parseLikeField(QueryParseContext parseContext, List<String> texts, List<Item> items) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java index 032feac919..0d93b1331b 100644 --- a/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/MultiMatchQueryBuilder.java @@ -43,6 +43,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.TreeMap; /** @@ -556,7 +557,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery builder.endObject(); } - public static MultiMatchQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<MultiMatchQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); Object value = null; @@ -660,7 +661,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery "Fuziness not allowed for type [" + type.parseField.getPreferredName() + "]"); } - return new MultiMatchQueryBuilder(value) + return Optional.of(new MultiMatchQueryBuilder(value) .fields(fieldsBoosts) .type(type) .analyzer(analyzer) @@ -677,7 +678,7 @@ public class MultiMatchQueryBuilder extends AbstractQueryBuilder<MultiMatchQuery .tieBreaker(tieBreaker) .zeroTermsQuery(zeroTermsQuery) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } private static void parseFieldAndBoost(XContentParser parser, Map<String, Float> fieldsBoosts) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java index 5d74b54011..1d0e6d11f5 100644 --- a/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.mapper.object.ObjectMapper; import java.io.IOException; import java.util.Map; import java.util.Objects; +import java.util.Optional; public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder> { @@ -156,12 +157,12 @@ public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder> builder.endObject(); } - public static NestedQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<NestedQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; ScoreMode scoreMode = ScoreMode.Avg; String queryName = null; - QueryBuilder query = null; + Optional<QueryBuilder> query = Optional.empty(); String path = null; String currentFieldName = null; InnerHitBuilder innerHitBuilder = null; @@ -194,14 +195,19 @@ public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder> } } } - NestedQueryBuilder queryBuilder = new NestedQueryBuilder(path, query, scoreMode) + + if (query.isPresent() == false) { + // if inner query is empty, bubble this up to caller so they can decide how to deal with it + return Optional.empty(); + } + NestedQueryBuilder queryBuilder = new NestedQueryBuilder(path, query.get(), scoreMode) .ignoreUnmapped(ignoreUnmapped) .queryName(queryName) .boost(boost); if (innerHitBuilder != null) { queryBuilder.innerHit(innerHitBuilder); } - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java index 419149ce99..ede449cbd3 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java @@ -38,6 +38,7 @@ import org.elasticsearch.index.mapper.internal.TypeFieldMapper; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public final class ParentIdQueryBuilder extends AbstractQueryBuilder<ParentIdQueryBuilder> { @@ -117,7 +118,7 @@ public final class ParentIdQueryBuilder extends AbstractQueryBuilder<ParentIdQue builder.endObject(); } - public static ParentIdQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<ParentIdQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; String type = null; @@ -151,7 +152,7 @@ public final class ParentIdQueryBuilder extends AbstractQueryBuilder<ParentIdQue queryBuilder.queryName(queryName); queryBuilder.boost(boost); queryBuilder.ignoreUnmapped(ignoreUnmapped); - return queryBuilder; + return Optional.of(queryBuilder); } diff --git a/core/src/main/java/org/elasticsearch/index/query/PrefixQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/PrefixQueryBuilder.java index 44677d1840..f92e1d521d 100644 --- a/core/src/main/java/org/elasticsearch/index/query/PrefixQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/PrefixQueryBuilder.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.query.support.QueryParsers; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * A Query that matches documents containing terms with a specified prefix. @@ -118,7 +119,7 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder> builder.endObject(); } - public static PrefixQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<PrefixQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = parser.currentName(); @@ -163,10 +164,10 @@ public class PrefixQueryBuilder extends AbstractQueryBuilder<PrefixQueryBuilder> if (value == null) { throw new ParsingException(parser.getTokenLocation(), "No value specified for prefix query"); } - return new PrefixQueryBuilder(fieldName, value) + return Optional.of(new PrefixQueryBuilder(fieldName, value) .rewrite(rewrite) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryParseContext.java b/core/src/main/java/org/elasticsearch/index/query/QueryParseContext.java index 62662914fd..93bd07c7bf 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryParseContext.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryParseContext.java @@ -23,14 +23,19 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParseFieldMatcherSupplier; import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.indices.query.IndicesQueriesRegistry; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public class QueryParseContext implements ParseFieldMatcherSupplier { + private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(QueryParseContext.class)); + private static final ParseField CACHE = new ParseField("_cache").withAllDeprecated("Elasticsearch makes its own caching decisions"); private static final ParseField CACHE_KEY = new ParseField("_cache_key").withAllDeprecated("Filters are always used as cache keys"); @@ -62,7 +67,7 @@ public class QueryParseContext implements ParseFieldMatcherSupplier { if (token == XContentParser.Token.FIELD_NAME) { String fieldName = parser.currentName(); if ("query".equals(fieldName)) { - queryBuilder = parseInnerQueryBuilder(); + queryBuilder = parseInnerQueryBuilder().orElse(null); } else { throw new ParsingException(parser.getTokenLocation(), "request does not support [" + parser.currentName() + "]"); } @@ -82,7 +87,7 @@ public class QueryParseContext implements ParseFieldMatcherSupplier { /** * Parses a query excluding the query element that wraps it */ - public QueryBuilder parseInnerQueryBuilder() throws IOException { + public Optional<QueryBuilder> parseInnerQueryBuilder() throws IOException { // move to START object XContentParser.Token token; if (parser.currentToken() != XContentParser.Token.START_OBJECT) { @@ -93,8 +98,13 @@ public class QueryParseContext implements ParseFieldMatcherSupplier { } token = parser.nextToken(); if (token == XContentParser.Token.END_OBJECT) { - // empty query - return new EmptyQueryBuilder(); + // we encountered '{}' for a query clause + String msg = "query malformed, empty clause found at [" + parser.getTokenLocation() +"]"; + DEPRECATION_LOGGER.deprecated(msg); + if (parseFieldMatcher.isStrict()) { + throw new IllegalArgumentException(msg); + } + return Optional.empty(); } if (token != XContentParser.Token.FIELD_NAME) { throw new ParsingException(parser.getTokenLocation(), "[_na] query malformed, no field after start_object"); @@ -105,7 +115,9 @@ public class QueryParseContext implements ParseFieldMatcherSupplier { if (token != XContentParser.Token.START_OBJECT && token != XContentParser.Token.START_ARRAY) { throw new ParsingException(parser.getTokenLocation(), "[_na] query malformed, no field after start_object"); } - QueryBuilder result = indicesQueriesRegistry.lookup(queryName, parseFieldMatcher, parser.getTokenLocation()).fromXContent(this); + @SuppressWarnings("unchecked") + Optional<QueryBuilder> result = (Optional<QueryBuilder>) indicesQueriesRegistry.lookup(queryName, parseFieldMatcher, + parser.getTokenLocation()).fromXContent(this); if (parser.currentToken() == XContentParser.Token.END_OBJECT || parser.currentToken() == XContentParser.Token.END_ARRAY) { // if we are at END_OBJECT, move to the next one... parser.nextToken(); diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryParser.java b/core/src/main/java/org/elasticsearch/index/query/QueryParser.java index 069dc86cf8..222d3bd496 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryParser.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryParser.java @@ -20,6 +20,7 @@ package org.elasticsearch.index.query; import java.io.IOException; +import java.util.Optional; /** * Defines a query parser that is able to parse {@link QueryBuilder}s from {@link org.elasticsearch.common.xcontent.XContent}. @@ -36,5 +37,12 @@ public interface QueryParser<QB extends QueryBuilder> { * call * @return the new QueryBuilder */ - QB fromXContent(QueryParseContext parseContext) throws IOException; + Optional<QB> fromXContent(QueryParseContext parseContext) throws IOException; + + /** + * @return an empty {@link QueryBuilder} instance for this parser that can be used for deserialization + */ + default QB getBuilderPrototype() { // TODO remove this when nothing implements it + throw new UnsupportedOperationException(); + } } diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java index 6806ae944c..c390507a78 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryStringQueryBuilder.java @@ -46,6 +46,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.TreeMap; /** @@ -631,7 +632,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue builder.endObject(); } - public static QueryStringQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<QueryStringQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String currentFieldName = null; XContentParser.Token token; @@ -792,7 +793,7 @@ public class QueryStringQueryBuilder extends AbstractQueryBuilder<QueryStringQue queryStringQuery.locale(locale); queryStringQuery.boost(boost); queryStringQuery.queryName(queryName); - return queryStringQuery; + return Optional.of(queryStringQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java index 241c38475a..1c51b6a2dd 100644 --- a/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/RangeQueryBuilder.java @@ -42,6 +42,7 @@ import org.joda.time.DateTimeZone; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * A Query that matches documents within an range of terms. @@ -297,7 +298,7 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i builder.endObject(); } - public static RangeQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<RangeQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -381,7 +382,7 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i if (format != null) { rangeQuery.format(format); } - return rangeQuery; + return Optional.of(rangeQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java index 703b2463b1..27462cfb26 100644 --- a/core/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/RegexpQueryBuilder.java @@ -37,6 +37,7 @@ import org.elasticsearch.index.query.support.QueryParsers; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * A Query that does fuzzy matching for a specific value. @@ -179,7 +180,7 @@ public class RegexpQueryBuilder extends AbstractQueryBuilder<RegexpQueryBuilder> builder.endObject(); } - public static RegexpQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<RegexpQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = parser.currentName(); @@ -237,12 +238,12 @@ public class RegexpQueryBuilder extends AbstractQueryBuilder<RegexpQueryBuilder> if (value == null) { throw new ParsingException(parser.getTokenLocation(), "No value specified for regexp query"); } - return new RegexpQueryBuilder(fieldName, value) + return Optional.of(new RegexpQueryBuilder(fieldName, value) .flags(flagsValue) .maxDeterminizedStates(maxDeterminizedStates) .rewrite(rewrite) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java index 12aba8ae87..6d563f22a0 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/ScriptQueryBuilder.java @@ -35,9 +35,9 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.LeafSearchScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.Script.ScriptField; -import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptParameterParser; +import org.elasticsearch.script.ScriptParameterParser.ScriptParameterValue; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.lookup.SearchLookup; @@ -47,6 +47,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; public class ScriptQueryBuilder extends AbstractQueryBuilder<ScriptQueryBuilder> { @@ -94,7 +95,7 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder<ScriptQueryBuilder> builder.endObject(); } - public static ScriptQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<ScriptQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); ScriptParameterParser scriptParameterParser = new ScriptParameterParser(); @@ -149,9 +150,9 @@ public class ScriptQueryBuilder extends AbstractQueryBuilder<ScriptQueryBuilder> throw new ParsingException(parser.getTokenLocation(), "script must be provided with a [script] filter"); } - return new ScriptQueryBuilder(script) + return Optional.of(new ScriptQueryBuilder(script) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java index 5e2c88af92..0bedf67820 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SimpleQueryStringBuilder.java @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.TreeMap; /** @@ -417,7 +418,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt builder.endObject(); } - public static SimpleQueryStringBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SimpleQueryStringBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String currentFieldName = null; @@ -514,7 +515,7 @@ public class SimpleQueryStringBuilder extends AbstractQueryBuilder<SimpleQuerySt qb.boost(boost).fields(fieldsAndWeights).analyzer(analyzerName).queryName(queryName).minimumShouldMatch(minimumShouldMatch); qb.flags(flags).defaultOperator(defaultOperator).locale(locale).lowercaseExpandedTerms(lowercaseExpandedTerms); qb.lenient(lenient).analyzeWildcard(analyzeWildcard).boost(boost); - return qb; + return Optional.of(qb); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanContainingQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanContainingQueryBuilder.java index ae4297e431..5d22df1557 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanContainingQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanContainingQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Builder for {@link org.apache.lucene.search.spans.SpanContainingQuery}. @@ -102,7 +103,7 @@ public class SpanContainingQueryBuilder extends AbstractQueryBuilder<SpanContain builder.endObject(); } - public static SpanContainingQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanContainingQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; String queryName = null; @@ -116,17 +117,17 @@ public class SpanContainingQueryBuilder extends AbstractQueryBuilder<SpanContain currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, BIG_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "span_containing [big] must be of type span query"); } - big = (SpanQueryBuilder) query; + big = (SpanQueryBuilder) query.get(); } else if (parseContext.getParseFieldMatcher().match(currentFieldName, LITTLE_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "span_containing [little] must be of type span query"); } - little = (SpanQueryBuilder) query; + little = (SpanQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[span_containing] query does not support [" + currentFieldName + "]"); @@ -143,7 +144,7 @@ public class SpanContainingQueryBuilder extends AbstractQueryBuilder<SpanContain SpanContainingQueryBuilder query = new SpanContainingQueryBuilder(big, little); query.boost(boost).queryName(queryName); - return query; + return Optional.of(query); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanFirstQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanFirstQueryBuilder.java index 009f8a3965..b0b096b19e 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanFirstQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanFirstQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public class SpanFirstQueryBuilder extends AbstractQueryBuilder<SpanFirstQueryBuilder> implements SpanQueryBuilder { @@ -101,7 +102,7 @@ public class SpanFirstQueryBuilder extends AbstractQueryBuilder<SpanFirstQueryBu builder.endObject(); } - public static SpanFirstQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanFirstQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -117,11 +118,11 @@ public class SpanFirstQueryBuilder extends AbstractQueryBuilder<SpanFirstQueryBu currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, MATCH_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "spanFirst [match] must be of type span query"); } - match = (SpanQueryBuilder) query; + match = (SpanQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[span_first] query does not support [" + currentFieldName + "]"); } @@ -145,7 +146,7 @@ public class SpanFirstQueryBuilder extends AbstractQueryBuilder<SpanFirstQueryBu } SpanFirstQueryBuilder queryBuilder = new SpanFirstQueryBuilder(match, end); queryBuilder.boost(boost).queryName(queryName); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java index 86418903f7..0849d1c6a6 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanMultiTermQueryBuilder.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Query that allows wraping a {@link MultiTermQueryBuilder} (one of wildcard, fuzzy, prefix, term, range or regexp query) @@ -82,7 +83,7 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer builder.endObject(); } - public static SpanMultiTermQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanMultiTermQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String currentFieldName = null; MultiTermQueryBuilder subQuery = null; @@ -94,12 +95,12 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, MATCH_FIELD)) { - QueryBuilder innerQuery = parseContext.parseInnerQueryBuilder(); - if (innerQuery instanceof MultiTermQueryBuilder == false) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof MultiTermQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "[span_multi] [" + MATCH_FIELD.getPreferredName() + "] must be of type multi term query"); } - subQuery = (MultiTermQueryBuilder) innerQuery; + subQuery = (MultiTermQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[span_multi] query does not support [" + currentFieldName + "]"); } @@ -119,7 +120,7 @@ public class SpanMultiTermQueryBuilder extends AbstractQueryBuilder<SpanMultiTer "[span_multi] must have [" + MATCH_FIELD.getPreferredName() + "] multi term query clause"); } - return new SpanMultiTermQueryBuilder(subQuery).queryName(queryName).boost(boost); + return Optional.of(new SpanMultiTermQueryBuilder(subQuery).queryName(queryName).boost(boost)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanNearQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanNearQueryBuilder.java index cebc72c077..c11164ae7a 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanNearQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanNearQueryBuilder.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Matches spans which are near one another. One can specify slop, the maximum number @@ -146,7 +147,7 @@ public class SpanNearQueryBuilder extends AbstractQueryBuilder<SpanNearQueryBuil builder.endObject(); } - public static SpanNearQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanNearQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -164,11 +165,11 @@ public class SpanNearQueryBuilder extends AbstractQueryBuilder<SpanNearQueryBuil } else if (token == XContentParser.Token.START_ARRAY) { if (parseContext.getParseFieldMatcher().match(currentFieldName, CLAUSES_FIELD)) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "spanNear [clauses] must be of type span query"); } - clauses.add((SpanQueryBuilder) query); + clauses.add((SpanQueryBuilder) query.get()); } } else { throw new ParsingException(parser.getTokenLocation(), "[span_near] query does not support [" + currentFieldName + "]"); @@ -207,7 +208,7 @@ public class SpanNearQueryBuilder extends AbstractQueryBuilder<SpanNearQueryBuil queryBuilder.inOrder(inOrder); queryBuilder.boost(boost); queryBuilder.queryName(queryName); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java index 02ce431de1..6bb635b200 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanNotQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public class SpanNotQueryBuilder extends AbstractQueryBuilder<SpanNotQueryBuilder> implements SpanQueryBuilder { @@ -162,7 +163,7 @@ public class SpanNotQueryBuilder extends AbstractQueryBuilder<SpanNotQueryBuilde builder.endObject(); } - public static SpanNotQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanNotQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -183,17 +184,17 @@ public class SpanNotQueryBuilder extends AbstractQueryBuilder<SpanNotQueryBuilde currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, INCLUDE_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "spanNot [include] must be of type span query"); } - include = (SpanQueryBuilder) query; + include = (SpanQueryBuilder) query.get(); } else if (parseContext.getParseFieldMatcher().match(currentFieldName, EXCLUDE_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "spanNot [exclude] must be of type span query"); } - exclude = (SpanQueryBuilder) query; + exclude = (SpanQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[span_not] query does not support [" + currentFieldName + "]"); } @@ -235,7 +236,7 @@ public class SpanNotQueryBuilder extends AbstractQueryBuilder<SpanNotQueryBuilde } spanNotQuery.boost(boost); spanNotQuery.queryName(queryName); - return spanNotQuery; + return Optional.of(spanNotQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanOrQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanOrQueryBuilder.java index 98698307d0..5169e0d933 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanOrQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanOrQueryBuilder.java @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Span query that matches the union of its clauses. Maps to {@link SpanOrQuery}. @@ -99,7 +100,7 @@ public class SpanOrQueryBuilder extends AbstractQueryBuilder<SpanOrQueryBuilder> builder.endObject(); } - public static SpanOrQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanOrQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -115,11 +116,11 @@ public class SpanOrQueryBuilder extends AbstractQueryBuilder<SpanOrQueryBuilder> } else if (token == XContentParser.Token.START_ARRAY) { if (parseContext.getParseFieldMatcher().match(currentFieldName, CLAUSES_FIELD)) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (!(query instanceof SpanQueryBuilder)) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "spanOr [clauses] must be of type span query"); } - clauses.add((SpanQueryBuilder) query); + clauses.add((SpanQueryBuilder) query.get()); } } else { throw new ParsingException(parser.getTokenLocation(), "[span_or] query does not support [" + currentFieldName + "]"); @@ -145,7 +146,7 @@ public class SpanOrQueryBuilder extends AbstractQueryBuilder<SpanOrQueryBuilder> } queryBuilder.boost(boost); queryBuilder.queryName(queryName); - return queryBuilder; + return Optional.of(queryBuilder); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanTermQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanTermQueryBuilder.java index 3bb374ff27..56581c3991 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanTermQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanTermQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.MappedFieldType; import java.io.IOException; +import java.util.Optional; /** * A Span Query that matches documents containing a term. @@ -93,7 +94,7 @@ public class SpanTermQueryBuilder extends BaseTermQueryBuilder<SpanTermQueryBuil return new SpanTermQuery(term); } - public static SpanTermQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { + public static Optional<SpanTermQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException, ParsingException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.currentToken(); @@ -142,7 +143,7 @@ public class SpanTermQueryBuilder extends BaseTermQueryBuilder<SpanTermQueryBuil SpanTermQueryBuilder result = new SpanTermQueryBuilder(fieldName, value); result.boost(boost).queryName(queryName); - return result; + return Optional.of(result); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/SpanWithinQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/SpanWithinQueryBuilder.java index eaedc80bab..2975063f78 100644 --- a/core/src/main/java/org/elasticsearch/index/query/SpanWithinQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/SpanWithinQueryBuilder.java @@ -31,6 +31,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Builder for {@link org.apache.lucene.search.spans.SpanWithinQuery}. @@ -107,7 +108,7 @@ public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQuery builder.endObject(); } - public static SpanWithinQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<SpanWithinQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -122,17 +123,17 @@ public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQuery currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, BIG_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (query instanceof SpanQueryBuilder == false) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "span_within [big] must be of type span query"); } - big = (SpanQueryBuilder) query; + big = (SpanQueryBuilder) query.get(); } else if (parseContext.getParseFieldMatcher().match(currentFieldName, LITTLE_FIELD)) { - QueryBuilder query = parseContext.parseInnerQueryBuilder(); - if (query instanceof SpanQueryBuilder == false) { + Optional<QueryBuilder> query = parseContext.parseInnerQueryBuilder(); + if (query.isPresent() == false || query.get() instanceof SpanQueryBuilder == false) { throw new ParsingException(parser.getTokenLocation(), "span_within [little] must be of type span query"); } - little = (SpanQueryBuilder) query; + little = (SpanQueryBuilder) query.get(); } else { throw new ParsingException(parser.getTokenLocation(), "[span_within] query does not support [" + currentFieldName + "]"); @@ -155,7 +156,7 @@ public class SpanWithinQueryBuilder extends AbstractQueryBuilder<SpanWithinQuery SpanWithinQueryBuilder query = new SpanWithinQueryBuilder(big, little); query.boost(boost).queryName(queryName); - return query; + return Optional.of(query); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java index 1a4d05374b..3b41abbbe8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/TemplateQueryBuilder.java @@ -21,6 +21,7 @@ package org.elasticsearch.index.query; import org.apache.lucene.search.Query; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseFieldMatcher; +import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -37,6 +38,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * Facilitates creating template query requests. @@ -120,10 +122,10 @@ public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuil * In the simplest case, parse template string and variables from the request, * compile the template and execute the template against the given variables. */ - public static TemplateQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<TemplateQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); Template template = parse(parser, parseContext.getParseFieldMatcher()); - return new TemplateQueryBuilder(template); + return Optional.of(new TemplateQueryBuilder(template)); } public static Template parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher, String... parameters) throws IOException { @@ -179,7 +181,8 @@ public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuil BytesReference querySource = (BytesReference) executable.run(); try (XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource)) { final QueryParseContext queryParseContext = queryRewriteContext.newParseContext(qSourceParser); - final QueryBuilder queryBuilder = queryParseContext.parseInnerQueryBuilder(); + final QueryBuilder queryBuilder = queryParseContext.parseInnerQueryBuilder().orElseThrow( + () -> new ParsingException(qSourceParser.getTokenLocation(), "inner query in [" + NAME + "] cannot be empty"));; if (boost() != DEFAULT_BOOST || queryName() != null) { final BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.must(queryBuilder); diff --git a/core/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java index ffdf6a3337..bfb55c9956 100644 --- a/core/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/TermQueryBuilder.java @@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.MappedFieldType; import java.io.IOException; +import java.util.Optional; /** * A Query that matches documents containing a term. @@ -84,7 +85,7 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> { super(in); } - public static TermQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<TermQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String queryName = null; @@ -140,7 +141,7 @@ public class TermQueryBuilder extends BaseTermQueryBuilder<TermQueryBuilder> { if (queryName != null) { termQuery.queryName(queryName); } - return termQuery; + return Optional.of(termQuery); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/TermsQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/TermsQueryBuilder.java index 5b0650eb7e..7d27a911f8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/TermsQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/TermsQueryBuilder.java @@ -47,6 +47,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -238,7 +239,7 @@ public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> { builder.endObject(); } - public static TermsQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<TermsQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); String fieldName = null; @@ -289,9 +290,9 @@ public class TermsQueryBuilder extends AbstractQueryBuilder<TermsQueryBuilder> { throw new ParsingException(parser.getTokenLocation(), "[" + TermsQueryBuilder.NAME + "] query requires a field name, " + "followed by array of terms or a document lookup specification"); } - return new TermsQueryBuilder(fieldName, values, termsLookup) + return Optional.of(new TermsQueryBuilder(fieldName, values, termsLookup) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } private static List<Object> parseValues(XContentParser parser) throws IOException { diff --git a/core/src/main/java/org/elasticsearch/index/query/TypeQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/TypeQueryBuilder.java index 129b027552..00cd108c00 100644 --- a/core/src/main/java/org/elasticsearch/index/query/TypeQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/TypeQueryBuilder.java @@ -33,6 +33,7 @@ import org.elasticsearch.index.mapper.DocumentMapper; import java.io.IOException; import java.util.Objects; +import java.util.Optional; public class TypeQueryBuilder extends AbstractQueryBuilder<TypeQueryBuilder> { public static final String NAME = "type"; @@ -81,7 +82,7 @@ public class TypeQueryBuilder extends AbstractQueryBuilder<TypeQueryBuilder> { builder.endObject(); } - public static TypeQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<TypeQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); BytesRef type = null; @@ -114,9 +115,9 @@ public class TypeQueryBuilder extends AbstractQueryBuilder<TypeQueryBuilder> { throw new ParsingException(parser.getTokenLocation(), "[" + TypeQueryBuilder.NAME + "] filter needs to be provided with a value for the type"); } - return new TypeQueryBuilder(type) + return Optional.of(new TypeQueryBuilder(type) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } diff --git a/core/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java index ef49472b8c..007dff9234 100644 --- a/core/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/WildcardQueryBuilder.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.query.support.QueryParsers; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * Implements the wildcard search query. Supported wildcards are <tt>*</tt>, which @@ -135,7 +136,7 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil builder.endObject(); } - public static WildcardQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<WildcardQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -180,10 +181,10 @@ public class WildcardQueryBuilder extends AbstractQueryBuilder<WildcardQueryBuil if (value == null) { throw new ParsingException(parser.getTokenLocation(), "No value specified for wildcard query"); } - return new WildcardQueryBuilder(fieldName, value) + return Optional.of(new WildcardQueryBuilder(fieldName, value) .rewrite(rewrite) .boost(boost) - .queryName(queryName); + .queryName(queryName)); } @Override diff --git a/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java index 4037666393..4e1eb83272 100644 --- a/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/WrapperQueryBuilder.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Optional; /** * A Query builder which allows building a query given JSON string or binary data provided as input. This is useful when you want @@ -116,7 +117,7 @@ public class WrapperQueryBuilder extends AbstractQueryBuilder<WrapperQueryBuilde builder.endObject(); } - public static WrapperQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<WrapperQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); XContentParser.Token token = parser.nextToken(); @@ -136,7 +137,7 @@ public class WrapperQueryBuilder extends AbstractQueryBuilder<WrapperQueryBuilde if (source == null) { throw new ParsingException(parser.getTokenLocation(), "wrapper query has no [query] specified"); } - return new WrapperQueryBuilder(source); + return Optional.of(new WrapperQueryBuilder(source)); } @Override @@ -164,7 +165,8 @@ public class WrapperQueryBuilder extends AbstractQueryBuilder<WrapperQueryBuilde try (XContentParser qSourceParser = XContentFactory.xContent(source).createParser(source)) { QueryParseContext parseContext = context.newParseContext(qSourceParser); - final QueryBuilder queryBuilder = parseContext.parseInnerQueryBuilder(); + final QueryBuilder queryBuilder = parseContext.parseInnerQueryBuilder().orElseThrow( + () -> new ParsingException(qSourceParser.getTokenLocation(), "inner query cannot be empty")); if (boost() != DEFAULT_BOOST || queryName() != null) { final BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.must(queryBuilder); diff --git a/core/src/main/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilder.java index 98f878d1c2..3e52322d22 100644 --- a/core/src/main/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilder.java @@ -37,12 +37,13 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentLocation; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.InnerHitBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.QueryShardContext; -import org.elasticsearch.index.query.InnerHitBuilder; import java.io.IOException; import java.util.ArrayList; @@ -51,6 +52,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * A query that uses a filters with a script associated with them to compute the @@ -431,15 +433,13 @@ public class FunctionScoreQueryBuilder extends AbstractQueryBuilder<FunctionScor return this; } - - @Override protected void extractInnerHitBuilders(Map<String, InnerHitBuilder> innerHits) { InnerHitBuilder.extractInnerHits(query(), innerHits); } - public static FunctionScoreQueryBuilder fromXContent(ParseFieldRegistry<ScoreFunctionParser<?>> scoreFunctionsRegistry, - QueryParseContext parseContext) throws IOException { + public static Optional<FunctionScoreQueryBuilder> fromXContent(ParseFieldRegistry<ScoreFunctionParser<?>> scoreFunctionsRegistry, + QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); QueryBuilder query = null; @@ -468,7 +468,7 @@ public class FunctionScoreQueryBuilder extends AbstractQueryBuilder<FunctionScor throw new ParsingException(parser.getTokenLocation(), "failed to parse [{}] query. [query] is already defined.", NAME); } - query = parseContext.parseInnerQueryBuilder(); + query = parseContext.parseInnerQueryBuilder().orElse(QueryBuilders.matchAllQuery()); } else { if (singleFunctionFound) { throw new ParsingException(parser.getTokenLocation(), @@ -556,7 +556,7 @@ public class FunctionScoreQueryBuilder extends AbstractQueryBuilder<FunctionScor } functionScoreQueryBuilder.boost(boost); functionScoreQueryBuilder.queryName(queryName); - return functionScoreQueryBuilder; + return Optional.of(functionScoreQueryBuilder); } private static void handleMisplacedFunctionsDeclaration(XContentLocation contentLocation, String errorString) { @@ -584,7 +584,7 @@ public class FunctionScoreQueryBuilder extends AbstractQueryBuilder<FunctionScor currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.START_OBJECT) { if (parseContext.getParseFieldMatcher().match(currentFieldName, FILTER_FIELD)) { - filter = parseContext.parseInnerQueryBuilder(); + filter = parseContext.parseInnerQueryBuilder().orElse(QueryBuilders.matchAllQuery()); } else { if (scoreFunction != null) { throw new ParsingException(parser.getTokenLocation(), diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java index a8893c4c27..8afda85c58 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchModule.java +++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java @@ -37,7 +37,6 @@ import org.elasticsearch.index.query.BoostingQueryBuilder; import org.elasticsearch.index.query.CommonTermsQueryBuilder; import org.elasticsearch.index.query.ConstantScoreQueryBuilder; import org.elasticsearch.index.query.DisMaxQueryBuilder; -import org.elasticsearch.index.query.EmptyQueryBuilder; import org.elasticsearch.index.query.ExistsQueryBuilder; import org.elasticsearch.index.query.FieldMaskingSpanQueryBuilder; import org.elasticsearch.index.query.FuzzyQueryBuilder; @@ -698,9 +697,6 @@ public class SearchModule extends AbstractModule { if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) { registerQuery(GeoShapeQueryBuilder::new, GeoShapeQueryBuilder::fromXContent, GeoShapeQueryBuilder.QUERY_NAME_FIELD); } - // EmptyQueryBuilder is not registered as query parser but used internally. - // We need to register it with the NamedWriteableRegistry in order to serialize it - namedWriteableRegistry.register(QueryBuilder.class, EmptyQueryBuilder.NAME, EmptyQueryBuilder::new); } static { diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregationBuilder.java index a971035b5f..a973d69da4 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filter/FilterAggregationBuilder.java @@ -24,8 +24,6 @@ import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.index.query.EmptyQueryBuilder; -import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.aggregations.AbstractAggregationBuilder; @@ -55,11 +53,7 @@ public class FilterAggregationBuilder extends AbstractAggregationBuilder<FilterA if (filter == null) { throw new IllegalArgumentException("[filter] must not be null: [" + name + "]"); } - if (filter instanceof EmptyQueryBuilder) { - this.filter = new MatchAllQueryBuilder(); - } else { - this.filter = filter; - } + this.filter = filter; } /** @@ -89,18 +83,12 @@ public class FilterAggregationBuilder extends AbstractAggregationBuilder<FilterA return builder; } - public static FilterAggregationBuilder parse(String aggregationName, QueryParseContext context) - throws IOException { - QueryBuilder filter = context.parseInnerQueryBuilder(); - - if (filter == null) { - throw new ParsingException(null, "filter cannot be null in filter aggregation [{}]", aggregationName); - } - + public static FilterAggregationBuilder parse(String aggregationName, QueryParseContext context) throws IOException { + QueryBuilder filter = context.parseInnerQueryBuilder().orElseThrow(() -> new ParsingException(context.parser().getTokenLocation(), + "filter cannot be null in filter aggregation [{}]", aggregationName)); return new FilterAggregationBuilder(aggregationName, filter); } - @Override protected int doHashCode() { return Objects.hash(filter); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregationBuilder.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregationBuilder.java index 5056e3a67b..9b2b9cee7f 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregationBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregationBuilder.java @@ -26,7 +26,6 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.aggregations.AbstractAggregationBuilder; import org.elasticsearch.search.aggregations.AggregatorFactories.Builder; @@ -235,8 +234,8 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter if (token == XContentParser.Token.FIELD_NAME) { key = parser.currentName(); } else { - QueryBuilder filter = context.parseInnerQueryBuilder(); - keyedFilters.add(new FiltersAggregator.KeyedFilter(key, filter == null ? matchAllQuery() : filter)); + QueryBuilder filter = context.parseInnerQueryBuilder().orElse(matchAllQuery()); + keyedFilters.add(new FiltersAggregator.KeyedFilter(key, filter)); } } } else { @@ -247,8 +246,8 @@ public class FiltersAggregationBuilder extends AbstractAggregationBuilder<Filter if (context.getParseFieldMatcher().match(currentFieldName, FILTERS_FIELD)) { nonKeyedFilters = new ArrayList<>(); while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { - QueryBuilder filter = context.parseInnerQueryBuilder(); - nonKeyedFilters.add(filter == null ? QueryBuilders.matchAllQuery() : filter); + QueryBuilder filter = context.parseInnerQueryBuilder().orElse(matchAllQuery()); + nonKeyedFilters.add(filter); } } else { throw new ParsingException(parser.getTokenLocation(), diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregator.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregator.java index a5ce89c466..08bbdaf3e3 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregator.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/filters/FiltersAggregator.java @@ -29,7 +29,6 @@ import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.index.query.EmptyQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.aggregations.Aggregator; @@ -69,11 +68,7 @@ public class FiltersAggregator extends BucketsAggregator { throw new IllegalArgumentException("[filter] must not be null"); } this.key = key; - if (filter instanceof EmptyQueryBuilder) { - this.filter = new MatchAllQueryBuilder(); - } else { - this.filter = filter; - } + this.filter = filter; } /** diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsParser.java b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsParser.java index 33db8f9733..ba87f0917a 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsParser.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/bucket/significant/SignificantTermsParser.java @@ -38,6 +38,7 @@ import org.elasticsearch.search.aggregations.support.ValuesSourceType; import java.io.IOException; import java.util.Map; +import java.util.Optional; /** * @@ -91,8 +92,10 @@ public class SignificantTermsParser extends AbstractTermsParser { return true; } else if (parseFieldMatcher.match(currentFieldName, SignificantTermsAggregationBuilder.BACKGROUND_FILTER)) { QueryParseContext queryParseContext = new QueryParseContext(queriesRegistry, parser, parseFieldMatcher); - QueryBuilder filter = queryParseContext.parseInnerQueryBuilder(); - otherOptions.put(SignificantTermsAggregationBuilder.BACKGROUND_FILTER, filter); + Optional<QueryBuilder> filter = queryParseContext.parseInnerQueryBuilder(); + if (filter.isPresent()) { + otherOptions.put(SignificantTermsAggregationBuilder.BACKGROUND_FILTER, filter.get()); + } return true; } } diff --git a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java index a2c2f3a0fa..4c47304330 100644 --- a/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/builder/SearchSourceBuilder.java @@ -611,7 +611,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ /** * Add an aggregation to perform as part of the search. */ - public SearchSourceBuilder aggregation(PipelineAggregatorBuilder aggregation) { + public SearchSourceBuilder aggregation(PipelineAggregatorBuilder<?> aggregation) { if (aggregations == null) { aggregations = AggregatorFactories.builder(); } @@ -1003,9 +1003,9 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ } } else if (token == XContentParser.Token.START_OBJECT) { if (context.getParseFieldMatcher().match(currentFieldName, QUERY_FIELD)) { - queryBuilder = context.parseInnerQueryBuilder(); + queryBuilder = context.parseInnerQueryBuilder().orElse(null); } else if (context.getParseFieldMatcher().match(currentFieldName, POST_FILTER_FIELD)) { - postQueryBuilder = context.parseInnerQueryBuilder(); + postQueryBuilder = context.parseInnerQueryBuilder().orElse(null); } else if (context.getParseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) { fetchSourceContext = FetchSourceContext.parse(context); } else if (context.getParseFieldMatcher().match(currentFieldName, SCRIPT_FIELDS_FIELD)) { diff --git a/core/src/main/java/org/elasticsearch/search/highlight/AbstractHighlighterBuilder.java b/core/src/main/java/org/elasticsearch/search/highlight/AbstractHighlighterBuilder.java index 557567fe35..816be79a9e 100644 --- a/core/src/main/java/org/elasticsearch/search/highlight/AbstractHighlighterBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/highlight/AbstractHighlighterBuilder.java @@ -539,7 +539,7 @@ public abstract class AbstractHighlighterBuilder<HB extends AbstractHighlighterB }, OPTIONS_FIELD); parser.declareObject(HB::highlightQuery, (XContentParser p, QueryParseContext c) -> { try { - return c.parseInnerQueryBuilder(); + return c.parseInnerQueryBuilder().orElse(null); } catch (IOException e) { throw new RuntimeException("Error parsing query", e); } diff --git a/core/src/main/java/org/elasticsearch/search/rescore/QueryRescorerBuilder.java b/core/src/main/java/org/elasticsearch/search/rescore/QueryRescorerBuilder.java index e91468c805..6f59b446dc 100644 --- a/core/src/main/java/org/elasticsearch/search/rescore/QueryRescorerBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/rescore/QueryRescorerBuilder.java @@ -26,6 +26,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.search.rescore.QueryRescorer.QueryRescoreContext; @@ -56,7 +57,7 @@ public class QueryRescorerBuilder extends RescoreBuilder<QueryRescorerBuilder> { static { QUERY_RESCORE_PARSER.declareObject(InnerBuilder::setQueryBuilder, (p, c) -> { try { - return c.parseInnerQueryBuilder(); + return c.parseInnerQueryBuilder().orElse(QueryBuilders.matchAllQuery()); } catch (IOException e) { throw new ParsingException(p.getTokenLocation(), "Could not parse inner query", e); } diff --git a/core/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java b/core/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java index 892673f890..d519f74087 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/sort/FieldSortBuilder.java @@ -39,6 +39,7 @@ import org.elasticsearch.search.MultiValueMode; import java.io.IOException; import java.util.Objects; +import java.util.Optional; /** * A sort builder to sort based on a document field. @@ -328,7 +329,7 @@ public class FieldSortBuilder extends SortBuilder<FieldSortBuilder> { public static FieldSortBuilder fromXContent(QueryParseContext context, String fieldName) throws IOException { XContentParser parser = context.parser(); - QueryBuilder nestedFilter = null; + Optional<QueryBuilder> nestedFilter = Optional.empty(); String nestedPath = null; Object missing = null; SortOrder order = null; @@ -371,9 +372,7 @@ public class FieldSortBuilder extends SortBuilder<FieldSortBuilder> { } FieldSortBuilder builder = new FieldSortBuilder(fieldName); - if (nestedFilter != null) { - builder.setNestedFilter(nestedFilter); - } + nestedFilter.ifPresent(builder::setNestedFilter); if (nestedPath != null) { builder.setNestedPath(nestedPath); } diff --git a/core/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java b/core/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java index dce9a7ec3f..f33dd0e2b1 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/sort/GeoDistanceSortBuilder.java @@ -60,6 +60,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Objects; +import java.util.Optional; /** * A geo distance based sorting on a geo point like field. @@ -257,7 +258,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder> } /** - * Sets validation method for this sort builder. + * Sets validation method for this sort builder. */ public GeoDistanceSortBuilder validation(GeoValidationMethod method) { this.validation = method; @@ -265,7 +266,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder> } /** - * Returns the validation method to use for this sort builder. + * Returns the validation method to use for this sort builder. */ public GeoValidationMethod validation() { return validation; @@ -407,7 +408,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder> GeoDistance geoDistance = GeoDistance.DEFAULT; SortOrder order = SortOrder.ASC; SortMode sortMode = null; - QueryBuilder nestedFilter = null; + Optional<QueryBuilder> nestedFilter = Optional.empty(); String nestedPath = null; boolean coerce = GeoValidationMethod.DEFAULT_LENIENT_PARSING; @@ -492,7 +493,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder> if (sortMode != null) { result.sortMode(sortMode); } - result.setNestedFilter(nestedFilter); + nestedFilter.ifPresent(result::setNestedFilter); result.setNestedPath(nestedPath); if (validation == null) { // looks like either validation was left unset or we are parsing old validation json @@ -517,7 +518,7 @@ public class GeoDistanceSortBuilder extends SortBuilder<GeoDistanceSortBuilder> for (GeoPoint point : localPoints) { if (GeoUtils.isValidLatitude(point.lat()) == false) { throw new ElasticsearchParseException( - "illegal latitude value [{}] for [GeoDistanceSort] for field [{}].", + "illegal latitude value [{}] for [GeoDistanceSort] for field [{}].", point.lat(), fieldName); } diff --git a/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java b/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java index eeb418c0a9..f7baee509d 100644 --- a/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java +++ b/core/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java @@ -61,6 +61,7 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Optional; /** * Script sort builder allows to sort based on a custom script expression. @@ -237,7 +238,7 @@ public class ScriptSortBuilder extends SortBuilder<ScriptSortBuilder> { ScriptSortType type = null; SortMode sortMode = null; SortOrder order = null; - QueryBuilder nestedFilter = null; + Optional<QueryBuilder> nestedFilter = Optional.empty(); String nestedPath = null; Map<String, Object> params = new HashMap<>(); @@ -292,9 +293,7 @@ public class ScriptSortBuilder extends SortBuilder<ScriptSortBuilder> { if (sortMode != null) { result.sortMode(sortMode); } - if (nestedFilter != null) { - result.setNestedFilter(nestedFilter); - } + nestedFilter.ifPresent(result::setNestedFilter); if (nestedPath != null) { result.setNestedPath(nestedPath); } diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java index 9aed90f55e..25f589794f 100644 --- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java +++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggester.java @@ -34,7 +34,9 @@ import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.query.MatchNoneQueryBuilder; import org.elasticsearch.index.query.ParsedQuery; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.script.CompiledScript; @@ -53,6 +55,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; public final class PhraseSuggester extends Suggester<PhraseSuggestionContext> { private final BytesRef SEPARATOR = new BytesRef(" "); @@ -123,7 +126,8 @@ public final class PhraseSuggester extends Suggester<PhraseSuggestionContext> { final ExecutableScript executable = scriptService.executable(collateScript, vars); final BytesReference querySource = (BytesReference) executable.run(); try (XContentParser parser = XContentFactory.xContent(querySource).createParser(querySource)) { - final ParsedQuery parsedQuery = shardContext.toQuery(shardContext.newParseContext(parser).parseInnerQueryBuilder()); + Optional<QueryBuilder> innerQueryBuilder = shardContext.newParseContext(parser).parseInnerQueryBuilder(); + final ParsedQuery parsedQuery = shardContext.toQuery(innerQueryBuilder.orElse(new MatchNoneQueryBuilder())); collateMatch = Lucene.exists(searcher, parsedQuery.query()); } } diff --git a/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java index 15180b9d98..89da227df8 100644 --- a/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/BoolQueryBuilderTests.java @@ -24,6 +24,7 @@ import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; @@ -43,6 +44,7 @@ import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.startsWith; public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilder> { @Override @@ -345,6 +347,29 @@ public class BoolQueryBuilderTests extends AbstractQueryTestCase<BoolQueryBuilde assertEquals(query, "kimchy", ((TermQueryBuilder)queryBuilder.must().get(0)).value()); } + /** + * we ignore empty query bodies if we are not in strict mode + */ + public void testFromJsonEmptyQueryBody() throws IOException { + String query = + "{" + + "\"bool\" : {" + + " \"must\" : [ { } ]," + + " \"filter\" : { }," + + " \"must_not\" : [ { \"constant_score\" : {\"filter\" : { } } } ]" + + "}" + + "}"; + + BoolQueryBuilder queryBuilder = (BoolQueryBuilder) parseQuery(query, ParseFieldMatcher.EMPTY); + assertEquals(query, 0, queryBuilder.must().size()); + assertEquals(query, 0, queryBuilder.filter().size()); + assertEquals(query, 0, queryBuilder.mustNot().size()); + assertEquals(query, 0, queryBuilder.should().size()); + + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> parseQuery(query, ParseFieldMatcher.STRICT)); + assertThat(ex.getMessage(), startsWith("query malformed, empty clause found at")); + } + public void testRewrite() throws IOException { BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolean mustRewrite = false; diff --git a/core/src/test/java/org/elasticsearch/index/query/BoostingQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/BoostingQueryBuilderTests.java index 34c15d6357..343c627074 100644 --- a/core/src/test/java/org/elasticsearch/index/query/BoostingQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/BoostingQueryBuilderTests.java @@ -21,12 +21,17 @@ package org.elasticsearch.index.query; import org.apache.lucene.queries.BoostingQuery; import org.apache.lucene.search.Query; +import org.elasticsearch.common.ParseFieldMatcher; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; +import java.util.Optional; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith;; public class BoostingQueryBuilderTests extends AbstractQueryTestCase<BoostingQueryBuilder> { @@ -105,6 +110,40 @@ public class BoostingQueryBuilderTests extends AbstractQueryTestCase<BoostingQue assertEquals(query, 5, queryBuilder.positiveQuery().boost(), 0.00001); } + /** + * we bubble up empty inner clauses as an empty optional + */ + public void testFromJsonEmptyQueryBody() throws IOException { + String query = + "{ \"boosting\" : {" + + " \"positive\" : { }, " + + " \"negative\" : { \"match_all\" : {} }, " + + " \"negative_boost\" : 23.0" + + " }" + + "}"; + XContentParser parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext context = createParseContext(parser, ParseFieldMatcher.EMPTY); + Optional<QueryBuilder> innerQueryBuilder = context.parseInnerQueryBuilder(); + assertTrue(innerQueryBuilder.isPresent() == false); + + query = + "{ \"boosting\" : {" + + " \"positive\" : { \"match_all\" : {} }, " + + " \"negative\" : { }, " + + " \"negative_boost\" : 23.0" + + " }" + + "}"; + parser = XContentFactory.xContent(query).createParser(query); + context = createParseContext(parser, ParseFieldMatcher.EMPTY); + innerQueryBuilder = context.parseInnerQueryBuilder(); + assertTrue(innerQueryBuilder.isPresent() == false); + + parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext otherContext = createParseContext(parser, ParseFieldMatcher.STRICT); + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> otherContext.parseInnerQueryBuilder()); + assertThat(ex.getMessage(), startsWith("query malformed, empty clause found at")); + } + public void testRewrite() throws IOException { QueryBuilder positive = randomBoolean() ? new MatchAllQueryBuilder() : new WrapperQueryBuilder(new TermQueryBuilder("pos", "bar").toString()); QueryBuilder negative = randomBoolean() ? new MatchAllQueryBuilder() : new WrapperQueryBuilder(new TermQueryBuilder("neg", "bar").toString()); diff --git a/core/src/test/java/org/elasticsearch/index/query/ConstantScoreQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/ConstantScoreQueryBuilderTests.java index c24dd25b98..86381c135a 100644 --- a/core/src/test/java/org/elasticsearch/index/query/ConstantScoreQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/ConstantScoreQueryBuilderTests.java @@ -21,13 +21,18 @@ package org.elasticsearch.index.query; import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.Query; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParsingException; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; +import java.util.Optional; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.containsString; public class ConstantScoreQueryBuilderTests extends AbstractQueryTestCase<ConstantScoreQueryBuilder> { @@ -126,4 +131,24 @@ public class ConstantScoreQueryBuilderTests extends AbstractQueryTestCase<Consta assertEquals(json, 42.0, parsed.innerQuery().boost(), 0.0001); } + /** + * we bubble up empty query bodies as an empty optional + */ + public void testFromJsonEmptyQueryBody() throws IOException { + String query = + "{ \"constant_score\" : {" + + " \"filter\" : { }" + + " }" + + "}"; + XContentParser parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext context = createParseContext(parser, ParseFieldMatcher.EMPTY); + Optional<QueryBuilder> innerQueryBuilder = context.parseInnerQueryBuilder(); + assertTrue(innerQueryBuilder.isPresent() == false); + + parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext otherContext = createParseContext(parser, ParseFieldMatcher.STRICT); + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> otherContext.parseInnerQueryBuilder()); + assertThat(ex.getMessage(), startsWith("query malformed, empty clause found at")); + } + } diff --git a/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java index 6d2348660c..61c786d1b0 100644 --- a/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/DisMaxQueryBuilderTests.java @@ -24,6 +24,7 @@ import org.apache.lucene.search.BoostQuery; import org.apache.lucene.search.DisjunctionMaxQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; @@ -96,15 +97,16 @@ public class DisMaxQueryBuilderTests extends AbstractQueryTestCase<DisMaxQueryBu } /** - * Test inner query parsing to null. Current DSL allows inner filter element to parse to <tt>null</tt>. - * Those should be ignored upstream. To test this, we use inner {@link ConstantScoreQueryBuilder} - * with empty inner filter. + * Test with empty inner query body, this should be ignored upstream. + * To test this, we use inner {@link ConstantScoreQueryBuilder} with empty inner filter. */ - public void testInnerQueryReturnsNull() throws IOException { - String queryString = "{ \"" + ConstantScoreQueryBuilder.NAME + "\" : { \"filter\" : { } } }"; - QueryBuilder innerQueryBuilder = parseQuery(queryString); - DisMaxQueryBuilder disMaxBuilder = new DisMaxQueryBuilder().add(innerQueryBuilder); - assertNull(disMaxBuilder.toQuery(createShardContext())); + public void testInnerQueryEmptyIgnored() throws IOException { + String queryString = "{ \"" + DisMaxQueryBuilder.NAME + "\" :" + + " { \"queries\" : [ {\"" + ConstantScoreQueryBuilder.NAME + "\" : { \"filter\" : { } } } ] " + + " }" + + " }"; + DisMaxQueryBuilder builder = (DisMaxQueryBuilder) parseQuery(queryString, ParseFieldMatcher.EMPTY); + assertTrue("the inner query has an empty body, so it should be ignored", builder.innerQueries().isEmpty()); } public void testIllegalArguments() { diff --git a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java index 1c6a99ca09..d0a924be0a 100644 --- a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java @@ -35,9 +35,12 @@ import org.apache.lucene.search.similarities.Similarity; import org.apache.lucene.util.BytesRef; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.internal.TypeFieldMapper; @@ -56,11 +59,13 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.is; public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQueryBuilder> { @@ -116,16 +121,11 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue @Override protected void doAssertLuceneQuery(HasChildQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { - QueryBuilder innerQueryBuilder = queryBuilder.query(); - if (innerQueryBuilder instanceof EmptyQueryBuilder) { - assertNull(query); - } else { - assertThat(query, instanceOf(HasChildQueryBuilder.LateParsingQuery.class)); - HasChildQueryBuilder.LateParsingQuery lpq = (HasChildQueryBuilder.LateParsingQuery) query; - assertEquals(queryBuilder.minChildren(), lpq.getMinChildren()); - assertEquals(queryBuilder.maxChildren(), lpq.getMaxChildren()); - assertEquals(queryBuilder.scoreMode(), lpq.getScoreMode()); // WTF is this why do we have two? - } + assertThat(query, instanceOf(HasChildQueryBuilder.LateParsingQuery.class)); + HasChildQueryBuilder.LateParsingQuery lpq = (HasChildQueryBuilder.LateParsingQuery) query; + assertEquals(queryBuilder.minChildren(), lpq.getMinChildren()); + assertEquals(queryBuilder.maxChildren(), lpq.getMaxChildren()); + assertEquals(queryBuilder.scoreMode(), lpq.getScoreMode()); // WTF is this why do we have two? if (queryBuilder.innerHit() != null) { SearchContext searchContext = SearchContext.current(); assertNotNull(searchContext); @@ -224,8 +224,29 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue .setSize(100) .addSort(new FieldSortBuilder("mapped_string").order(SortOrder.ASC)); assertEquals(query, queryBuilder.innerHit(), expected); + } + /** + * we resolve empty inner clauses by representing this whole query as empty optional upstream + */ + public void testFromJsonEmptyQueryBody() throws IOException { + String query = "{\n" + + " \"has_child\" : {\n" + + " \"query\" : { },\n" + + " \"type\" : \"child\"" + + " }" + + "}"; + XContentParser parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext context = createParseContext(parser, ParseFieldMatcher.EMPTY); + Optional<QueryBuilder> innerQueryBuilder = context.parseInnerQueryBuilder(); + assertTrue(innerQueryBuilder.isPresent() == false); + + parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext otherContext = createParseContext(parser, ParseFieldMatcher.STRICT); + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> otherContext.parseInnerQueryBuilder()); + assertThat(ex.getMessage(), startsWith("query malformed, empty clause found at")); } + public void testToQueryInnerQueryType() throws IOException { String[] searchTypes = new String[]{PARENT_TYPE}; QueryShardContext shardContext = createShardContext(); diff --git a/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java index 7b700cbfc7..c4ba395db5 100644 --- a/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java @@ -32,6 +32,7 @@ import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.script.Script.ScriptParseException; import org.elasticsearch.search.fetch.innerhits.InnerHitsContext; @@ -45,11 +46,13 @@ import org.junit.BeforeClass; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.startsWith; public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQueryBuilder> { protected static final String PARENT_TYPE = "parent"; @@ -99,14 +102,10 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ @Override protected void doAssertLuceneQuery(HasParentQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { - QueryBuilder innerQueryBuilder = queryBuilder.query(); - if (innerQueryBuilder instanceof EmptyQueryBuilder) { - assertNull(query); - } else { - assertThat(query, instanceOf(HasChildQueryBuilder.LateParsingQuery.class)); - HasChildQueryBuilder.LateParsingQuery lpq = (HasChildQueryBuilder.LateParsingQuery) query; - assertEquals(queryBuilder.score() ? ScoreMode.Max : ScoreMode.None, lpq.getScoreMode()); - } + assertThat(query, instanceOf(HasChildQueryBuilder.LateParsingQuery.class)); + HasChildQueryBuilder.LateParsingQuery lpq = (HasChildQueryBuilder.LateParsingQuery) query; + assertEquals(queryBuilder.score() ? ScoreMode.Max : ScoreMode.None, lpq.getScoreMode()); + if (queryBuilder.innerHit() != null) { SearchContext searchContext = SearchContext.current(); assertNotNull(searchContext); @@ -231,6 +230,27 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ assertEquals(json, "something", ((TermQueryBuilder) parsed.query()).value()); } + /** + * we resolve empty inner clauses by representing this whole query as empty optional upstream + */ + public void testFromJsonEmptyQueryBody() throws IOException { + String query = "{\n" + + " \"has_parent\" : {\n" + + " \"query\" : { },\n" + + " \"parent_type\" : \"blog\"" + + " }" + + "}"; + XContentParser parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext context = createParseContext(parser, ParseFieldMatcher.EMPTY); + Optional<QueryBuilder> innerQueryBuilder = context.parseInnerQueryBuilder(); + assertTrue(innerQueryBuilder.isPresent() == false); + + parser = XContentFactory.xContent(query).createParser(query); + QueryParseContext otherContext = createParseContext(parser, ParseFieldMatcher.STRICT); + IllegalArgumentException ex = expectThrows(IllegalArgumentException.class, () -> otherContext.parseInnerQueryBuilder()); + assertThat(ex.getMessage(), startsWith("query malformed, empty clause found at")); + } + public void testIgnoreUnmapped() throws IOException { final HasParentQueryBuilder queryBuilder = new HasParentQueryBuilder("unmapped", new MatchAllQueryBuilder(), false); queryBuilder.ignoreUnmapped(true); diff --git a/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java index 04bbadb02c..d93bcce6dc 100644 --- a/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java @@ -83,13 +83,9 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu @Override protected void doAssertLuceneQuery(NestedQueryBuilder queryBuilder, Query query, QueryShardContext context) throws IOException { QueryBuilder innerQueryBuilder = queryBuilder.query(); - if (innerQueryBuilder instanceof EmptyQueryBuilder) { - assertNull(query); - } else { - assertThat(query, instanceOf(ToParentBlockJoinQuery.class)); - ToParentBlockJoinQuery parentBlockJoinQuery = (ToParentBlockJoinQuery) query; - //TODO how to assert this? - } + assertThat(query, instanceOf(ToParentBlockJoinQuery.class)); + ToParentBlockJoinQuery parentBlockJoinQuery = (ToParentBlockJoinQuery) query; + // TODO how to assert this? if (queryBuilder.innerHit() != null) { SearchContext searchContext = SearchContext.current(); assertNotNull(searchContext); diff --git a/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java b/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java index cf4921b7a4..c244273d13 100644 --- a/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java +++ b/core/src/test/java/org/elasticsearch/index/query/RandomQueryBuilder.java @@ -38,7 +38,7 @@ public class RandomQueryBuilder { * @return a random {@link QueryBuilder} */ public static QueryBuilder createQuery(Random r) { - switch (RandomInts.randomIntBetween(r, 0, 4)) { + switch (RandomInts.randomIntBetween(r, 0, 3)) { case 0: return new MatchAllQueryBuilderTests().createTestQueryBuilder(); case 1: @@ -47,8 +47,6 @@ public class RandomQueryBuilder { return new IdsQueryBuilderTests().createTestQueryBuilder(); case 3: return createMultiTermQuery(r); - case 4: - return new EmptyQueryBuilder(); default: throw new UnsupportedOperationException(); } diff --git a/core/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java index a8bdeb6936..985669394d 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/TermsQueryBuilderTests.java @@ -239,25 +239,25 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil public void testNumeric() throws IOException { { TermsQueryBuilder builder = new TermsQueryBuilder("foo", new int[]{1, 3, 4}); - TermsQueryBuilder copy = assertSerialization(builder); + TermsQueryBuilder copy = (TermsQueryBuilder) assertSerialization(builder); List<Object> values = copy.values(); assertEquals(Arrays.asList(1, 3, 4), values); } { TermsQueryBuilder builder = new TermsQueryBuilder("foo", new double[]{1, 3, 4}); - TermsQueryBuilder copy = assertSerialization(builder); + TermsQueryBuilder copy = (TermsQueryBuilder) assertSerialization(builder); List<Object> values = copy.values(); assertEquals(Arrays.asList(1d, 3d, 4d), values); } { TermsQueryBuilder builder = new TermsQueryBuilder("foo", new float[]{1, 3, 4}); - TermsQueryBuilder copy = assertSerialization(builder); + TermsQueryBuilder copy = (TermsQueryBuilder) assertSerialization(builder); List<Object> values = copy.values(); assertEquals(Arrays.asList(1f, 3f, 4f), values); } { TermsQueryBuilder builder = new TermsQueryBuilder("foo", new long[]{1, 3, 4}); - TermsQueryBuilder copy = assertSerialization(builder); + TermsQueryBuilder copy = (TermsQueryBuilder) assertSerialization(builder); List<Object> values = copy.values(); assertEquals(Arrays.asList(1L, 3L, 4L), values); } diff --git a/core/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java index 52632edcf4..2597675095 100644 --- a/core/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/functionscore/FunctionScoreQueryBuilderTests.java @@ -26,6 +26,7 @@ import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.io.stream.StreamInput; @@ -599,8 +600,30 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi " }\n" + "}"; - FunctionScoreQueryBuilder parsed = (FunctionScoreQueryBuilder) parseQuery(json); - checkGeneratedJson(json, parsed); + FunctionScoreQueryBuilder parsed = (FunctionScoreQueryBuilder) parseQuery(json, ParseFieldMatcher.EMPTY); + // this should be equivalent to the same with a match_all query + String expected = + "{\n" + + " \"function_score\" : {\n" + + " \"query\" : { \"match_all\" : {} },\n" + + " \"functions\" : [ {\n" + + " \"filter\" : { },\n" + + " \"weight\" : 23.0,\n" + + " \"random_score\" : { }\n" + + " }, {\n" + + " \"filter\" : { },\n" + + " \"weight\" : 5.0\n" + + " } ],\n" + + " \"score_mode\" : \"multiply\",\n" + + " \"boost_mode\" : \"multiply\",\n" + + " \"max_boost\" : 100.0,\n" + + " \"min_score\" : 1.0,\n" + + " \"boost\" : 42.0\n" + + " }\n" + + "}"; + + FunctionScoreQueryBuilder expectedParsed = (FunctionScoreQueryBuilder) parseQuery(json, ParseFieldMatcher.EMPTY); + assertEquals(expectedParsed, parsed); assertEquals(json, 2, parsed.filterFunctionBuilders().length); assertEquals(json, 42, parsed.boost(), 0.0001); diff --git a/core/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserIT.java b/core/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserIT.java index ec405bd840..ba87b29370 100644 --- a/core/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserIT.java +++ b/core/src/test/java/org/elasticsearch/index/query/plugin/CustomQueryParserIT.java @@ -59,11 +59,11 @@ public class CustomQueryParserIT extends ESIntegTestCase { } public void testCustomDummyQuery() { - assertHitCount(client().prepareSearch("index").setQuery(new DummyQueryParserPlugin.DummyQueryBuilder()).get(), 1L); + assertHitCount(client().prepareSearch("index").setQuery(new DummyQueryBuilder()).get(), 1L); } public void testCustomDummyQueryWithinBooleanQuery() { - assertHitCount(client().prepareSearch("index").setQuery(new BoolQueryBuilder().must(new DummyQueryParserPlugin.DummyQueryBuilder())).get(), 1L); + assertHitCount(client().prepareSearch("index").setQuery(new BoolQueryBuilder().must(new DummyQueryBuilder())).get(), 1L); } private static QueryShardContext queryShardContext() { @@ -73,7 +73,7 @@ public class CustomQueryParserIT extends ESIntegTestCase { //see #11120 public void testConstantScoreParsesFilter() throws Exception { - Query q = constantScoreQuery(new DummyQueryParserPlugin.DummyQueryBuilder()).toQuery(queryShardContext()); + Query q = constantScoreQuery(new DummyQueryBuilder()).toQuery(queryShardContext()); Query inner = ((ConstantScoreQuery) q).getQuery(); assertThat(inner, instanceOf(DummyQueryParserPlugin.DummyQuery.class)); assertEquals(true, ((DummyQueryParserPlugin.DummyQuery) inner).isFilter); @@ -83,10 +83,10 @@ public class CustomQueryParserIT extends ESIntegTestCase { public void testBooleanParsesFilter() throws Exception { // single clause, serialized as inner object Query q = boolQuery() - .should(new DummyQueryParserPlugin.DummyQueryBuilder()) - .must(new DummyQueryParserPlugin.DummyQueryBuilder()) - .filter(new DummyQueryParserPlugin.DummyQueryBuilder()) - .mustNot(new DummyQueryParserPlugin.DummyQueryBuilder()).toQuery(queryShardContext()); + .should(new DummyQueryBuilder()) + .must(new DummyQueryBuilder()) + .filter(new DummyQueryBuilder()) + .mustNot(new DummyQueryBuilder()).toQuery(queryShardContext()); assertThat(q, instanceOf(BooleanQuery.class)); BooleanQuery bq = (BooleanQuery) q; assertEquals(4, bq.clauses().size()); @@ -108,10 +108,10 @@ public class CustomQueryParserIT extends ESIntegTestCase { // multiple clauses, serialized as inner arrays q = boolQuery() - .should(new DummyQueryParserPlugin.DummyQueryBuilder()).should(new DummyQueryParserPlugin.DummyQueryBuilder()) - .must(new DummyQueryParserPlugin.DummyQueryBuilder()).must(new DummyQueryParserPlugin.DummyQueryBuilder()) - .filter(new DummyQueryParserPlugin.DummyQueryBuilder()).filter(new DummyQueryParserPlugin.DummyQueryBuilder()) - .mustNot(new DummyQueryParserPlugin.DummyQueryBuilder()).mustNot(new DummyQueryParserPlugin.DummyQueryBuilder()).toQuery(queryShardContext()); + .should(new DummyQueryBuilder()).should(new DummyQueryBuilder()) + .must(new DummyQueryBuilder()).must(new DummyQueryBuilder()) + .filter(new DummyQueryBuilder()).filter(new DummyQueryBuilder()) + .mustNot(new DummyQueryBuilder()).mustNot(new DummyQueryBuilder()).toQuery(queryShardContext()); assertThat(q, instanceOf(BooleanQuery.class)); bq = (BooleanQuery) q; assertEquals(8, bq.clauses().size()); diff --git a/core/src/main/java/org/elasticsearch/index/query/EmptyQueryBuilder.java b/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryBuilder.java index 3d09bb41b0..334244559c 100644 --- a/core/src/main/java/org/elasticsearch/index/query/EmptyQueryBuilder.java +++ b/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryBuilder.java @@ -17,67 +17,66 @@ * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.index.query.plugin; import org.apache.lucene.search.Query; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.query.plugin.DummyQueryParserPlugin.DummyQuery; import java.io.IOException; +import java.util.Optional; -/** - * A {@link QueryBuilder} that is a stand in replacement for an empty query clause in the DSL. - * The current DSL allows parsing inner queries / filters like "{ }", in order to have a - * valid non-null representation of these clauses that actually do nothing we can use this class. - */ -public final class EmptyQueryBuilder extends AbstractQueryBuilder<EmptyQueryBuilder> { - - public static final String NAME = "empty_query"; +public class DummyQueryBuilder extends AbstractQueryBuilder<DummyQueryBuilder> { + private static final String NAME = "dummy"; + static final ParseField QUERY_NAME_FIELD = new ParseField(NAME); - /** - * Construct an empty query. This query can *technically* be named and given a boost. - */ - public EmptyQueryBuilder() { + public DummyQueryBuilder() { } - /** - * Read from a stream. - */ - public EmptyQueryBuilder(StreamInput in) throws IOException { + public DummyQueryBuilder(StreamInput in) throws IOException { super(in); } @Override protected void doWriteTo(StreamOutput out) throws IOException { + // only the superclass has state } @Override - public String getWriteableName() { - return NAME; + protected void doXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(NAME).endObject(); } - @Override - protected Query doToQuery(QueryShardContext context) throws IOException { - return null; + public static Optional<DummyQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { + XContentParser.Token token = parseContext.parser().nextToken(); + assert token == XContentParser.Token.END_OBJECT; + return Optional.of(new DummyQueryBuilder()); } @Override - public String getName() { - return getWriteableName(); + protected Query doToQuery(QueryShardContext context) throws IOException { + return new DummyQuery(context.isFilter()); } @Override - protected void doXContent(XContentBuilder builder, Params params) throws IOException { + protected int doHashCode() { + return 0; } @Override - protected int doHashCode() { - return 31; + protected boolean doEquals(DummyQueryBuilder other) { + return true; } @Override - protected boolean doEquals(EmptyQueryBuilder other) { - return true; + public String getWriteableName() { + return NAME; } -} +}
\ No newline at end of file diff --git a/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java b/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java index 54d1026a7f..fbb744f799 100644 --- a/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java +++ b/core/src/test/java/org/elasticsearch/index/query/plugin/DummyQueryParserPlugin.java @@ -23,14 +23,6 @@ import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.Weight; -import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.query.AbstractQueryBuilder; -import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.SearchModule; @@ -52,62 +44,11 @@ public class DummyQueryParserPlugin extends Plugin { module.registerQuery(DummyQueryBuilder::new, DummyQueryBuilder::fromXContent, DummyQueryBuilder.QUERY_NAME_FIELD); } - public static class DummyQueryBuilder extends AbstractQueryBuilder<DummyQueryBuilder> { - private static final String NAME = "dummy"; - private static final ParseField QUERY_NAME_FIELD = new ParseField(NAME); - - public DummyQueryBuilder() { - } - - /** - * Read from a stream. - */ - public DummyQueryBuilder(StreamInput in) throws IOException { - super(in); - } - - @Override - protected void doWriteTo(StreamOutput out) throws IOException { - // only the superclass has state - } - - @Override - protected void doXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(NAME).endObject(); - } - - public static DummyQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { - XContentParser.Token token = parseContext.parser().nextToken(); - assert token == XContentParser.Token.END_OBJECT; - return new DummyQueryBuilder(); - } - - @Override - protected Query doToQuery(QueryShardContext context) throws IOException { - return new DummyQuery(context.isFilter()); - } - - @Override - protected int doHashCode() { - return 0; - } - - @Override - protected boolean doEquals(DummyQueryBuilder other) { - return true; - } - - @Override - public String getWriteableName() { - return NAME; - } - } - public static class DummyQuery extends Query { public final boolean isFilter; private final Query matchAllDocsQuery = new MatchAllDocsQuery(); - private DummyQuery(boolean isFilter) { + public DummyQuery(boolean isFilter) { this.isFilter = isFilter; } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FilterIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FilterIT.java index 9859936b41..ddb62d57ff 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FilterIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FilterIT.java @@ -21,11 +21,17 @@ package org.elasticsearch.search.aggregations.bucket; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.BoolQueryBuilder; -import org.elasticsearch.index.query.EmptyQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.indices.query.IndicesQueriesRegistry; +import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filter.Filter; +import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; import org.elasticsearch.search.aggregations.metrics.avg.Avg; import org.elasticsearch.test.ESIntegTestCase; @@ -42,8 +48,8 @@ import static org.elasticsearch.search.aggregations.AggregationBuilders.filter; import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNull.notNullValue; /** @@ -119,9 +125,16 @@ public class FilterIT extends ESIntegTestCase { assertThat(filter.getDocCount(), equalTo((long) numDocs)); } + /** + * test that "{ "filter" : {} }" is regarded as match_all when not parsing strict + */ public void testEmptyFilter() throws Exception { - QueryBuilder emptyFilter = new EmptyQueryBuilder(); - SearchResponse response = client().prepareSearch("idx").addAggregation(filter("tag1", emptyFilter)).execute().actionGet(); + String emtpyFilterBody = "{ }"; + XContentParser parser = XContentFactory.xContent(emtpyFilterBody).createParser(emtpyFilterBody); + QueryParseContext parseContext = new QueryParseContext(new IndicesQueriesRegistry(), parser, ParseFieldMatcher.EMPTY); + AggregationBuilder<?> filterAgg = FilterAggregationBuilder.parse("tag1", parseContext); + + SearchResponse response = client().prepareSearch("idx").addAggregation(filterAgg).execute().actionGet(); assertSearchResponse(response); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersIT.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersIT.java index fd4db82f2d..0be0f76de9 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersIT.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/FiltersIT.java @@ -22,11 +22,17 @@ package org.elasticsearch.search.aggregations.bucket; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.query.BoolQueryBuilder; -import org.elasticsearch.index.query.EmptyQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.indices.query.IndicesQueriesRegistry; +import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filters.Filters; +import org.elasticsearch.search.aggregations.bucket.filters.FiltersAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filters.FiltersAggregator.KeyedFilter; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; import org.elasticsearch.search.aggregations.metrics.avg.Avg; @@ -207,8 +213,13 @@ public class FiltersIT extends ESIntegTestCase { } public void testEmptyFilter() throws Exception { - QueryBuilder emptyFilter = new EmptyQueryBuilder(); - SearchResponse response = client().prepareSearch("idx").addAggregation(filters("tag1", emptyFilter)).execute().actionGet(); + String emtpyFilterBody = "{ \"filters\" : [ {} ] }"; + XContentParser parser = XContentFactory.xContent(emtpyFilterBody).createParser(emtpyFilterBody); + parser.nextToken(); + QueryParseContext parseContext = new QueryParseContext(new IndicesQueriesRegistry(), parser, ParseFieldMatcher.EMPTY); + AggregationBuilder<?> filtersAgg = FiltersAggregationBuilder.parse("tag1", parseContext); + + SearchResponse response = client().prepareSearch("idx").addAggregation(filtersAgg).execute().actionGet(); assertSearchResponse(response); @@ -219,8 +230,13 @@ public class FiltersIT extends ESIntegTestCase { } public void testEmptyKeyedFilter() throws Exception { - QueryBuilder emptyFilter = new EmptyQueryBuilder(); - SearchResponse response = client().prepareSearch("idx").addAggregation(filters("tag1", new KeyedFilter("foo", emptyFilter))) + String emtpyFilterBody = "{ \"filters\" : {\"foo\" : {} } }"; + XContentParser parser = XContentFactory.xContent(emtpyFilterBody).createParser(emtpyFilterBody); + parser.nextToken(); + QueryParseContext parseContext = new QueryParseContext(new IndicesQueriesRegistry(), parser, ParseFieldMatcher.EMPTY); + AggregationBuilder<?> filtersAgg = FiltersAggregationBuilder.parse("tag1", parseContext); + + SearchResponse response = client().prepareSearch("idx").addAggregation(filtersAgg) .execute().actionGet(); assertSearchResponse(response); diff --git a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java index f8236f66e4..fc3c90b516 100644 --- a/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java @@ -48,8 +48,6 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.env.Environment; import org.elasticsearch.env.EnvironmentModule; import org.elasticsearch.index.Index; -import org.elasticsearch.test.AbstractQueryTestCase; -import org.elasticsearch.index.query.EmptyQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.indices.IndicesModule; @@ -80,6 +78,7 @@ import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.suggest.SuggestBuilderTests; import org.elasticsearch.search.suggest.Suggesters; +import org.elasticsearch.test.AbstractQueryTestCase; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.IndexSettingsModule; import org.elasticsearch.test.InternalSettingsPlugin; @@ -440,11 +439,17 @@ public class SearchSourceBuilderTests extends ESTestCase { assertParseSearchSource(testSearchSourceBuilder, builder.bytes()); } - private void assertParseSearchSource(SearchSourceBuilder testBuilder, BytesReference searchSourceAsBytes) throws IOException { + private static void assertParseSearchSource(SearchSourceBuilder testBuilder, BytesReference searchSourceAsBytes) throws IOException { + assertParseSearchSource(testBuilder, searchSourceAsBytes, ParseFieldMatcher.STRICT); + } + + private static void assertParseSearchSource(SearchSourceBuilder testBuilder, BytesReference searchSourceAsBytes, ParseFieldMatcher pfm) + throws IOException { XContentParser parser = XContentFactory.xContent(searchSourceAsBytes).createParser(searchSourceAsBytes); - QueryParseContext parseContext = createParseContext(parser); + QueryParseContext parseContext = new QueryParseContext(indicesQueriesRegistry, parser, pfm); if (randomBoolean()) { - parser.nextToken(); // sometimes we move it on the START_OBJECT to test the embedded case + parser.nextToken(); // sometimes we move it on the START_OBJECT to + // test the embedded case } SearchSourceBuilder newBuilder = SearchSourceBuilder.fromXContent(parseContext, aggParsers, suggesters); assertNull(parser.nextToken()); @@ -614,8 +619,13 @@ public class SearchSourceBuilderTests extends ESTestCase { public void testEmptyPostFilter() throws IOException { SearchSourceBuilder builder = new SearchSourceBuilder(); - builder.postFilter(new EmptyQueryBuilder()); String query = "{ \"post_filter\": {} }"; - assertParseSearchSource(builder, new BytesArray(query)); + assertParseSearchSource(builder, new BytesArray(query), ParseFieldMatcher.EMPTY); + } + + public void testEmptyQuery() throws IOException { + SearchSourceBuilder builder = new SearchSourceBuilder(); + String query = "{ \"query\": {} }"; + assertParseSearchSource(builder, new BytesArray(query), ParseFieldMatcher.EMPTY); } } diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java index 7097718c6f..9aa5e1892e 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java @@ -169,7 +169,7 @@ public class TemplateQueryParserTests extends ESTestCase { QueryShardContext context = contextFactory.get(); templateSourceParser.nextToken(); - Query query = QueryBuilder.rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)), + Query query = QueryBuilder.rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).get(), context).toQuery(context); assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); } @@ -180,7 +180,9 @@ public class TemplateQueryParserTests extends ESTestCase { XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString); QueryShardContext context = contextFactory.get(); - Query query = QueryBuilder.rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)), context).toQuery(context); + Query query = QueryBuilder + .rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).get(), context) + .toQuery(context); assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); } @@ -197,7 +199,7 @@ public class TemplateQueryParserTests extends ESTestCase { QueryShardContext context = contextFactory.get(); try { - TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).rewrite(context); + TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).get().rewrite(context); fail("Expected ParsingException"); } catch (ParsingException e) { assertThat(e.getMessage(), containsString("query malformed, no field after start_object")); @@ -212,7 +214,7 @@ public class TemplateQueryParserTests extends ESTestCase { templateSourceParser.nextToken(); - Query query = QueryBuilder.rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)), + Query query = QueryBuilder.rewriteQuery(TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).get(), context).toQuery(context); assertTrue("Parsing template query failed.", query instanceof MatchAllDocsQuery); } @@ -224,7 +226,7 @@ public class TemplateQueryParserTests extends ESTestCase { QueryShardContext context = contextFactory.get(); templateSourceParser.nextToken(); try { - TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).toQuery(context); + TemplateQueryBuilder.fromXContent(context.newParseContext(templateSourceParser)).get().toQuery(context); fail(); } catch (UnsupportedOperationException ex) { assertEquals("this query must be rewritten first", ex.getMessage()); diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQueryBuilder.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQueryBuilder.java index 627cb09da1..aadcabda00 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQueryBuilder.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolateQueryBuilder.java @@ -76,6 +76,7 @@ import org.elasticsearch.index.query.QueryShardException; import java.io.IOException; import java.util.List; import java.util.Objects; +import java.util.Optional; import static org.elasticsearch.index.mapper.SourceToParse.source; import static org.elasticsearch.percolator.PercolatorFieldMapper.parseQuery; @@ -235,7 +236,7 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu builder.endObject(); } - public static PercolateQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException { + public static Optional<PercolateQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException { XContentParser parser = parseContext.parser(); float boost = AbstractQueryBuilder.DEFAULT_BOOST; @@ -316,7 +317,7 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu } queryBuilder.queryName(queryName); queryBuilder.boost(boost); - return queryBuilder; + return Optional.of(queryBuilder); } @Override @@ -446,7 +447,7 @@ public class PercolateQueryBuilder extends AbstractQueryBuilder<PercolateQueryBu return document; } - private IndexSearcher createMultiDocumentSearcher(Analyzer analyzer, ParsedDocument doc) { + private static IndexSearcher createMultiDocumentSearcher(Analyzer analyzer, ParsedDocument doc) { IndexReader[] memoryIndices = new IndexReader[doc.docs().size()]; List<ParseContext.Document> docs = doc.docs(); int rootDocIndex = docs.size() - 1; diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java index bf5c4c0ae8..a19a207eb7 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java @@ -250,7 +250,8 @@ public class PercolatorFieldMapper extends FieldMapper { private static QueryBuilder parseQueryBuilder(QueryParseContext context, XContentLocation location) { try { - return context.parseInnerQueryBuilder(); + return context.parseInnerQueryBuilder() + .orElseThrow(() -> new ParsingException(location, "Failed to parse inner query, was empty")); } catch (IOException e) { throw new ParsingException(location, "Failed to parse", e); } diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/TransportPercolateAction.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/TransportPercolateAction.java index f3ee9230ea..9e86ae44cd 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/TransportPercolateAction.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/TransportPercolateAction.java @@ -42,7 +42,6 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.ConstantScoreQueryBuilder; -import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.indices.query.IndicesQueriesRegistry; @@ -202,9 +201,8 @@ public class TransportPercolateAction extends HandledTransportAction<PercolateRe if (querySource != null) { try (XContentParser parser = XContentHelper.createParser(querySource)) { QueryParseContext queryParseContext = new QueryParseContext(queryRegistry, parser, parseFieldMatcher); - QueryBuilder queryBuilder = queryParseContext.parseInnerQueryBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); - boolQueryBuilder.must(queryBuilder); + queryParseContext.parseInnerQueryBuilder().ifPresent(boolQueryBuilder::must); boolQueryBuilder.filter(percolateQueryBuilder); searchSource.field("query", boolQueryBuilder); } diff --git a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java index bcb9ed8d40..2175dabfef 100644 --- a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java +++ b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java @@ -272,6 +272,6 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase { XContentParser sourceParser = PercolatorFieldMapper.QUERY_BUILDER_CONTENT_TYPE.xContent() .createParser(actual.bytes, actual.offset, actual.length); QueryParseContext qsc = indexService.newQueryShardContext().newParseContext(sourceParser); - assertThat(qsc.parseInnerQueryBuilder(), equalTo(expected)); + assertThat(qsc.parseInnerQueryBuilder().get(), equalTo(expected)); } } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index c27617a728..2e0bfe2891 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -336,11 +336,11 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>> /** * Parses the query provided as string argument and compares it with the expected result provided as argument as a {@link QueryBuilder} */ - protected final void assertParsedQuery(String queryAsString, QueryBuilder expectedQuery) throws IOException { + protected final static void assertParsedQuery(String queryAsString, QueryBuilder expectedQuery) throws IOException { assertParsedQuery(queryAsString, expectedQuery, ParseFieldMatcher.STRICT); } - protected final void assertParsedQuery(String queryAsString, QueryBuilder expectedQuery, ParseFieldMatcher matcher) throws IOException { + protected final static void assertParsedQuery(String queryAsString, QueryBuilder expectedQuery, ParseFieldMatcher matcher) throws IOException { QueryBuilder newQuery = parseQuery(queryAsString, matcher); assertNotSame(newQuery, expectedQuery); assertEquals(expectedQuery, newQuery); @@ -350,38 +350,39 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>> /** * Parses the query provided as bytes argument and compares it with the expected result provided as argument as a {@link QueryBuilder} */ - protected final void assertParsedQuery(BytesReference queryAsBytes, QueryBuilder expectedQuery) throws IOException { + protected final static void assertParsedQuery(BytesReference queryAsBytes, QueryBuilder expectedQuery) throws IOException { assertParsedQuery(queryAsBytes, expectedQuery, ParseFieldMatcher.STRICT); } - protected final void assertParsedQuery(BytesReference queryAsBytes, QueryBuilder expectedQuery, ParseFieldMatcher matcher) throws IOException { + protected final static void assertParsedQuery(BytesReference queryAsBytes, QueryBuilder expectedQuery, ParseFieldMatcher matcher) throws IOException { QueryBuilder newQuery = parseQuery(queryAsBytes, matcher); assertNotSame(newQuery, expectedQuery); assertEquals(expectedQuery, newQuery); assertEquals(expectedQuery.hashCode(), newQuery.hashCode()); } - protected final QueryBuilder parseQuery(String queryAsString) throws IOException { + protected final static QueryBuilder parseQuery(String queryAsString) throws IOException { return parseQuery(queryAsString, ParseFieldMatcher.STRICT); } - protected final QueryBuilder parseQuery(String queryAsString, ParseFieldMatcher matcher) throws IOException { + protected final static QueryBuilder parseQuery(String queryAsString, ParseFieldMatcher matcher) throws IOException { XContentParser parser = XContentFactory.xContent(queryAsString).createParser(queryAsString); return parseQuery(parser, matcher); } - protected final QueryBuilder parseQuery(BytesReference queryAsBytes) throws IOException { + protected final static QueryBuilder parseQuery(BytesReference queryAsBytes) throws IOException { return parseQuery(queryAsBytes, ParseFieldMatcher.STRICT); } - protected final QueryBuilder parseQuery(BytesReference queryAsBytes, ParseFieldMatcher matcher) throws IOException { + protected final static QueryBuilder parseQuery(BytesReference queryAsBytes, ParseFieldMatcher matcher) throws IOException { XContentParser parser = XContentFactory.xContent(queryAsBytes).createParser(queryAsBytes); return parseQuery(parser, matcher); } - private QueryBuilder parseQuery(XContentParser parser, ParseFieldMatcher matcher) throws IOException { + private static QueryBuilder parseQuery(XContentParser parser, ParseFieldMatcher matcher) throws IOException { QueryParseContext context = createParseContext(parser, matcher); - QueryBuilder parseInnerQueryBuilder = context.parseInnerQueryBuilder(); + QueryBuilder parseInnerQueryBuilder = context.parseInnerQueryBuilder() + .orElseThrow(() -> new IllegalArgumentException("inner query body cannot be empty")); assertNull(parser.nextToken()); return parseInnerQueryBuilder; } @@ -518,8 +519,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>> /** * Serialize the given query builder and asserts that both are equal */ - @SuppressWarnings("unchecked") - protected <QB extends QueryBuilder> QB assertSerialization(QB testQuery) throws IOException { + protected QueryBuilder assertSerialization(QueryBuilder testQuery) throws IOException { try (BytesStreamOutput output = new BytesStreamOutput()) { output.writeNamedWriteable(testQuery); try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), serviceHolder.namedWriteableRegistry)) { @@ -527,7 +527,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>> assertEquals(testQuery, deserializedQuery); assertEquals(testQuery.hashCode(), deserializedQuery.hashCode()); assertNotSame(testQuery, deserializedQuery); - return (QB) deserializedQuery; + return deserializedQuery; } } } |