Remove "query" query and fix related parsing bugs

We have two types of parse methods for queries: one for the inner query, to be used once the parser is positioned within the query element, and one for the whole query source, including the query element that wraps the actual query.

With the search refactoring we ended up using the former in count, cat count and delete by query, whereas we should have used the former.  It ends up working properly given that we have a registered (deprecated) query called "query", which used to allow to wrap a filter into a query, but this has the following downsides:
1) prevents us from removing the deprecated "query" query
2) we end up supporting a top level query that is not wrapped within a query element (pre 1.0 syntax iirc that shouldn't be supported anymore)

This commit finally removes the "query" query and fixes the related parsing bugs. We also had some tests that were providing queries in the wrong format, those have been fixed too.

Closes #13326
Closes #14304
This commit is contained in:
javanna 2015-10-26 12:18:36 +01:00 committed by Luca Cavanna
parent dde5e83ff4
commit dc900a08a6
23 changed files with 165 additions and 377 deletions

View File

@ -179,7 +179,7 @@ public class TransportValidateQueryAction extends TransportBroadcastAction<Valid
SearchContext.setCurrent(searchContext);
try {
if (request.source() != null && request.source().length() > 0) {
searchContext.parsedQuery(queryParserService.parseQuery(request.source()));
searchContext.parsedQuery(queryParserService.parseTopLevelQuery(request.source()));
}
searchContext.preProcess();

View File

@ -121,7 +121,7 @@ public class TransportExplainAction extends TransportSingleShardAction<ExplainRe
SearchContext.setCurrent(context);
try {
context.parsedQuery(indexService.queryParserService().parseQuery(request.source()));
context.parsedQuery(indexService.queryParserService().parseTopLevelQuery(request.source()));
context.preProcess();
int topLevelDocId = result.docIdAndVersion().docId + result.docIdAndVersion().context.docBase;
Explanation explanation = context.searcher().explain(context.query(), topLevelDocId);

View File

@ -34,7 +34,6 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.search.Queries;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.IndexSettings;
@ -213,29 +212,20 @@ public class IndexQueryParserService extends AbstractIndexComponent {
/**
* Selectively parses a query from a top level query or query_binary json field from the specified source.
*/
public ParsedQuery parseQuery(BytesReference source) {
public ParsedQuery parseTopLevelQuery(BytesReference source) {
XContentParser parser = null;
try {
parser = XContentHelper.createParser(source);
ParsedQuery parsedQuery = null;
for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) {
if (token == XContentParser.Token.FIELD_NAME) {
String fieldName = parser.currentName();
if ("query".equals(fieldName)) {
parsedQuery = parse(parser);
} else if ("query_binary".equals(fieldName) || "queryBinary".equals(fieldName)) {
byte[] querySource = parser.binaryValue();
XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource);
parsedQuery = parse(qSourceParser);
} else {
throw new ParsingException(parser.getTokenLocation(), "request does not support [" + fieldName + "]");
}
}
parser = XContentFactory.xContent(source).createParser(source);
QueryShardContext queryShardContext = cache.get();
queryShardContext.reset(parser);
queryShardContext.parseFieldMatcher(parseFieldMatcher);
try {
QueryBuilder<?> queryBuilder = queryShardContext.parseContext().parseTopLevelQueryBuilder();
Query query = toQuery(queryBuilder, queryShardContext);
return new ParsedQuery(query, queryShardContext.copyNamedQueries());
} finally {
queryShardContext.reset(null);
}
if (parsedQuery == null) {
throw new ParsingException(parser.getTokenLocation(), "Required query is missing");
}
return parsedQuery;
} catch (ParsingException | QueryShardException e) {
throw e;
} catch (Throwable e) {

View File

@ -1,111 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.util.Objects;
/**
* A filter that simply wraps a query.
* @deprecated Useless now that queries and filters are merged: pass the
* query as a filter directly.
*/
//TODO: remove when https://github.com/elastic/elasticsearch/issues/13326 is fixed
@Deprecated
public class QueryFilterBuilder extends AbstractQueryBuilder<QueryFilterBuilder> {
public static final String NAME = "query";
private final QueryBuilder queryBuilder;
static final QueryFilterBuilder PROTOTYPE = new QueryFilterBuilder(EmptyQueryBuilder.PROTOTYPE);
/**
* A filter that simply wraps a query.
*
* @param queryBuilder The query to wrap as a filter
*/
public QueryFilterBuilder(QueryBuilder queryBuilder) {
if (queryBuilder == null) {
throw new IllegalArgumentException("inner query cannot be null");
}
this.queryBuilder = queryBuilder;
}
/**
* @return the query builder that is wrapped by this {@link QueryFilterBuilder}
*/
public QueryBuilder innerQuery() {
return this.queryBuilder;
}
@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.field(NAME);
queryBuilder.toXContent(builder, params);
}
@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
// inner query builder can potentially be `null`, in that case we ignore it
Query innerQuery = this.queryBuilder.toQuery(context);
if (innerQuery == null) {
return null;
}
return new ConstantScoreQuery(innerQuery);
}
@Override
protected void setFinalBoost(Query query) {
//no-op this query doesn't support boost
}
@Override
protected int doHashCode() {
return Objects.hash(queryBuilder);
}
@Override
protected boolean doEquals(QueryFilterBuilder other) {
return Objects.equals(queryBuilder, other.queryBuilder);
}
@Override
protected QueryFilterBuilder doReadFrom(StreamInput in) throws IOException {
QueryBuilder innerQueryBuilder = in.readQuery();
return new QueryFilterBuilder(innerQueryBuilder);
}
@Override
protected void doWriteTo(StreamOutput out) throws IOException {
out.writeQuery(queryBuilder);
}
@Override
public String getWriteableName() {
return NAME;
}
}

View File

@ -1,46 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
import java.io.IOException;
/**
* Parser for query filter
* @deprecated use any query instead directly, possible since queries and filters are merged.
*/
// TODO: remove when https://github.com/elastic/elasticsearch/issues/13326 is fixed
@Deprecated
public class QueryFilterParser implements QueryParser<QueryFilterBuilder> {
@Override
public String[] names() {
return new String[]{QueryFilterBuilder.NAME};
}
@Override
public QueryFilterBuilder fromXContent(QueryParseContext parseContext) throws IOException {
return new QueryFilterBuilder(parseContext.parseInnerQueryBuilder());
}
@Override
public QueryFilterBuilder getBuilderPrototype() {
return QueryFilterBuilder.PROTOTYPE;
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.index.query;
import org.elasticsearch.common.ParseField;
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.indices.query.IndicesQueriesRegistry;
@ -65,9 +66,47 @@ public class QueryParseContext {
}
/**
* @return a new QueryBuilder based on the current state of the parser
* Parses a top level query including the query element that wraps it
*/
public QueryBuilder parseInnerQueryBuilder() throws IOException {
public QueryBuilder<?> parseTopLevelQueryBuilder() {
try {
QueryBuilder<?> queryBuilder = null;
for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) {
if (token == XContentParser.Token.FIELD_NAME) {
String fieldName = parser.currentName();
if ("query".equals(fieldName)) {
queryBuilder = parseInnerQueryBuilder();
} else if ("query_binary".equals(fieldName) || "queryBinary".equals(fieldName)) {
byte[] querySource = parser.binaryValue();
XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource);
QueryParseContext queryParseContext = new QueryParseContext(indicesQueriesRegistry);
queryParseContext.reset(qSourceParser);
try {
queryParseContext.parseFieldMatcher(parseFieldMatcher);
queryBuilder = queryParseContext.parseInnerQueryBuilder();
} finally {
queryParseContext.reset(null);
}
} else {
throw new ParsingException(parser.getTokenLocation(), "request does not support [" + parser.currentName() + "]");
}
}
}
if (queryBuilder == null) {
throw new ParsingException(parser.getTokenLocation(), "Required query is missing");
}
return queryBuilder;
} catch (ParsingException e) {
throw e;
} catch (Throwable e) {
throw new ParsingException(parser == null ? null : parser.getTokenLocation(), "Failed to parse", e);
}
}
/**
* Parses a query excluding the query element that wraps it
*/
public QueryBuilder<?> parseInnerQueryBuilder() throws IOException {
// move to START object
XContentParser.Token token;
if (parser.currentToken() != XContentParser.Token.START_OBJECT) {

View File

@ -24,11 +24,9 @@ import org.elasticsearch.action.update.UpdateHelper;
import org.elasticsearch.cluster.metadata.MetaDataIndexUpgradeService;
import org.elasticsearch.common.geo.ShapesAvailability;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.ExtensionPoint;
import org.elasticsearch.index.query.*;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryParser;
import org.elasticsearch.index.query.MoreLikeThisQueryParser;
import org.elasticsearch.index.termvectors.TermVectorsService;
import org.elasticsearch.indices.analysis.HunspellService;
import org.elasticsearch.indices.analysis.IndicesAnalysisService;
@ -105,7 +103,6 @@ public class IndicesModule extends AbstractModule {
registerQueryParser(GeoBoundingBoxQueryParser.class);
registerQueryParser(GeohashCellQuery.Parser.class);
registerQueryParser(GeoPolygonQueryParser.class);
registerQueryParser(QueryFilterParser.class);
registerQueryParser(ExistsQueryParser.class);
registerQueryParser(MissingQueryParser.class);
registerQueryParser(MatchNoneQueryParser.class);

View File

@ -28,7 +28,6 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
@ -71,9 +70,7 @@ public class RestCountAction extends AbstractCatAction {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0);
countRequest.source(searchSourceBuilder);
if (source != null) {
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
context.parseFieldMatcher(parseFieldMatcher);
searchSourceBuilder.query(RestActions.getQueryContent(new BytesArray(source), context));
searchSourceBuilder.query(RestActions.getQueryContent(new BytesArray(source), indicesQueriesRegistry, parseFieldMatcher));
} else {
QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
if (queryBuilder != null) {

View File

@ -29,7 +29,6 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestActions;
@ -68,9 +67,7 @@ public class RestCountAction extends BaseRestHandler {
countRequest.source(searchSourceBuilder);
if (RestActions.hasBodyContent(request)) {
BytesReference restContent = RestActions.getRestContent(request);
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
context.parseFieldMatcher(parseFieldMatcher);
searchSourceBuilder.query(RestActions.getQueryContent(restContent, context));
searchSourceBuilder.query(RestActions.getQueryContent(restContent, indicesQueriesRegistry, parseFieldMatcher));
} else {
QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
if (queryBuilder != null) {

View File

@ -27,17 +27,8 @@ import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.index.query.*;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.search.builder.SearchSourceBuilder;
@ -142,14 +133,12 @@ public class RestActions {
return content;
}
public static QueryBuilder<?> getQueryContent(BytesReference source, QueryParseContext context) {
public static QueryBuilder<?> getQueryContent(BytesReference source, IndicesQueriesRegistry indicesQueriesRegistry, ParseFieldMatcher parseFieldMatcher) {
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
try (XContentParser requestParser = XContentFactory.xContent(source).createParser(source)) {
// Save the parseFieldMatcher because its about to be trashed in the
// QueryParseContext
ParseFieldMatcher parseFieldMatcher = context.parseFieldMatcher();
context.reset(requestParser);
context.parseFieldMatcher(parseFieldMatcher);
return context.parseInnerQueryBuilder();
return context.parseTopLevelQueryBuilder();
} catch (IOException e) {
throw new ElasticsearchException("failed to parse source", e);
} finally {

View File

@ -724,8 +724,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
} else if (context.parseFieldMatcher().match(currentFieldName, TRACK_SCORES_FIELD)) {
builder.trackScores = parser.booleanValue();
} else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
FetchSourceContext fetchSourceContext = FetchSourceContext.parse(parser, context);
builder.fetchSourceContext = fetchSourceContext;
builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
} else if (context.parseFieldMatcher().match(currentFieldName, FIELDS_FIELD)) {
List<String> fieldNames = new ArrayList<>();
fieldNames.add(parser.text());
@ -742,8 +741,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
} else if (context.parseFieldMatcher().match(currentFieldName, POST_FILTER_FIELD)) {
builder.postQueryBuilder = context.parseInnerQueryBuilder();
} else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
FetchSourceContext fetchSourceContext = FetchSourceContext.parse(parser, context);
builder.fetchSourceContext = fetchSourceContext;
builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
} else if (context.parseFieldMatcher().match(currentFieldName, SCRIPT_FIELDS_FIELD)) {
List<ScriptField> scriptFields = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -886,8 +884,7 @@ public final class SearchSourceBuilder extends ToXContentToBytes implements Writ
}
builder.stats = stats;
} else if (context.parseFieldMatcher().match(currentFieldName, _SOURCE_FIELD)) {
FetchSourceContext fetchSourceContext = FetchSourceContext.parse(parser, context);
builder.fetchSourceContext = fetchSourceContext;
builder.fetchSourceContext = FetchSourceContext.parse(parser, context);
} else {
throw new ParsingException(parser.getTokenLocation(), "Unknown key for a " + token + " in [" + currentFieldName + "].",
parser.getTokenLocation());

View File

@ -21,7 +21,6 @@ package org.elasticsearch.index.query;
import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator;
import com.fasterxml.jackson.core.io.JsonStringEncoder;
import org.apache.lucene.search.Query;
import org.elasticsearch.Version;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
@ -73,12 +72,7 @@ import org.elasticsearch.indices.IndicesWarmer;
import org.elasticsearch.indices.analysis.IndicesAnalysisService;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.*;
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.ESTestCase;
@ -99,12 +93,7 @@ import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ExecutionException;
import static org.hamcrest.Matchers.equalTo;
@ -220,8 +209,8 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
new AbstractModule() {
@Override
protected void configure() {
IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(index, indexSettings, Collections.EMPTY_LIST);
SimilarityService service = new SimilarityService(idxSettings, Collections.EMPTY_MAP);
IndexSettings idxSettings = IndexSettingsModule.newIndexSettings(index, indexSettings, Collections.emptyList());
SimilarityService service = new SimilarityService(idxSettings, Collections.emptyMap());
bind(SimilarityService.class).toInstance(service);
BitsetFilterCache bitsetFilterCache = new BitsetFilterCache(idxSettings, new IndicesWarmer(idxSettings.getNodeSettings(), null));
bind(BitsetFilterCache.class).toInstance(bitsetFilterCache);
@ -413,7 +402,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
/**
* Few queries allow you to set the boost and queryName on the java api, although the corresponding parser doesn't parse them as they are not supported.
* This method allows to disable boost and queryName related tests for those queries. Those queries are easy to identify: their parsers
* don't parse `boost` and `_name` as they don't apply to the specific query: filter query, wrapper query and match_none
* don't parse `boost` and `_name` as they don't apply to the specific query: wrapper query and match_none
*/
protected boolean supportsBoostAndQueryName() {
return true;

View File

@ -1,77 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.Query;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.nullValue;
@SuppressWarnings("deprecation")
public class QueryFilterBuilderTests extends AbstractQueryTestCase<QueryFilterBuilder> {
@Override
protected QueryFilterBuilder doCreateTestQueryBuilder() {
QueryBuilder innerQuery = RandomQueryBuilder.createQuery(random());
return new QueryFilterBuilder(innerQuery);
}
@Override
protected void doAssertLuceneQuery(QueryFilterBuilder queryBuilder, Query query, QueryShardContext context) throws IOException {
Query innerQuery = queryBuilder.innerQuery().toQuery(context);
if (innerQuery == null) {
assertThat(query, nullValue());
} else {
assertThat(query, instanceOf(ConstantScoreQuery.class));
ConstantScoreQuery constantScoreQuery = (ConstantScoreQuery) query;
assertThat(constantScoreQuery.getQuery(), equalTo(innerQuery));
}
}
@Override
protected boolean supportsBoostAndQueryName() {
return false;
}
/**
* test that wrapping an inner filter that returns <tt>null</tt> also returns <tt>null</tt> to pass on upwards
*/
public void testInnerQueryReturnsNull() throws IOException {
// create inner filter
String queryString = "{ \"constant_score\" : { \"filter\" : {} } }";
QueryBuilder<?> innerQuery = parseQuery(queryString);
// check that when wrapping this filter, toQuery() returns null
QueryFilterBuilder queryFilterQuery = new QueryFilterBuilder(innerQuery);
assertNull(queryFilterQuery.toQuery(createShardContext()));
}
public void testValidate() {
try {
new QueryFilterBuilder(null);
fail("cannot be null");
} catch (IllegalArgumentException e) {
// expected
}
}
}

View File

@ -88,23 +88,12 @@ public class TemplateQueryIT extends ESIntegTestCase {
}
public void testTemplateInBodyWithSize() throws IOException {
String request = "{\n" +
" \"size\":0," +
" \"query\": {\n" +
" \"template\": {\n" +
" \"query\": {\"match_{{template}}\": {}},\n" +
" \"params\" : {\n" +
" \"template\" : \"all\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
Map<String, Object> params = new HashMap<>();
params.put("template", "all");
SearchResponse sr = client().prepareSearch()
.setSource(
new SearchSourceBuilder().size(0).query(
QueryBuilders.templateQuery(new Template("{ \"query\": { \"match_{{template}}\": {} } }",
QueryBuilders.templateQuery(new Template("{ \"match_{{template}}\": {} }",
ScriptType.INLINE, null, null, params)))).execute()
.actionGet();
assertNoFailures(sr);

View File

@ -579,7 +579,6 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
public void testFieldValueFactorFactorArray() throws IOException {
// don't permit an array of factors
String querySource = "{" +
"\"query\": {" +
" \"function_score\": {" +
" \"query\": {" +
" \"match\": {\"name\": \"foo\"}" +
@ -593,7 +592,6 @@ public class FunctionScoreQueryBuilderTests extends AbstractQueryTestCase<Functi
" }" +
" ]" +
" }" +
" }" +
"}";
try {
parseQuery(querySource);

View File

@ -78,6 +78,16 @@ format can't read from version `3.0.0` and onwards. The new format allows for a
scalable join between parent and child documents and the join data structures are stored on on disk
data structures as opposed as before the join data structures were stored in the jvm heap space.
==== Deprecated queries removed
The following deprecated queries have been removed:
* `filtered`: use `bool` query instead, which supports `filter` clauses too
* `and`: use `must` clauses in a `bool` query instead
* `or`: use should clauses in a `bool` query instead
* `limit`: use `terminate_after` parameter instead
* `fquery`: obsolete after filters and queries have been merged
* `query`: obsolete after filters and queries have been merged
==== `score_type` has been removed
The `score_type` option has been removed from the `has_child` and `has_parent` queries in favour of the `score_mode` option

View File

@ -362,7 +362,7 @@ The filter cache has been renamed <<query-cache>>.
[role="exclude",id="query-dsl-filtered-query"]
=== Filtered query
The `filtered` query is replaced in favour of the <<query-dsl-bool-query,bool>> query. Instead of
The `filtered` query is replaced by the <<query-dsl-bool-query,bool>> query. Instead of
the following:
[source,js]

View File

@ -20,16 +20,12 @@
package org.elasticsearch.rest.action.deletebyquery;
import org.elasticsearch.action.deletebyquery.DeleteByQueryRequest;
import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestChannel;
@ -67,29 +63,15 @@ public class RestDeleteByQueryAction extends BaseRestHandler {
if (request.hasParam("timeout")) {
delete.timeout(request.paramAsTime("timeout", null));
}
if (request.hasContent()) {
XContentParser requestParser = XContentFactory.xContent(request.content()).createParser(request.content());
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
context.reset(requestParser);
context.parseFieldMatcher(parseFieldMatcher);
final QueryBuilder<?> builder = context.parseInnerQueryBuilder();
delete.query(builder);
if (RestActions.hasBodyContent(request)) {
delete.query(RestActions.getQueryContent(RestActions.getRestContent(request), indicesQueriesRegistry, parseFieldMatcher));
} else {
String source = request.param("source");
if (source != null) {
XContentParser requestParser = XContentFactory.xContent(source).createParser(source);
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
context.reset(requestParser);
final QueryBuilder<?> builder = context.parseInnerQueryBuilder();
delete.query(builder);
} else {
QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
if (queryBuilder != null) {
delete.query(queryBuilder);
}
QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
if (queryBuilder != null) {
delete.query(queryBuilder);
}
}
delete.types(Strings.splitStringByCommaToArray(request.param("type")));
client.execute(INSTANCE, delete, new RestToXContentListener<DeleteByQueryResponse>(channel));
client.execute(INSTANCE, delete, new RestToXContentListener<>(channel));
}
}

View File

@ -1,5 +1,4 @@
---
"Basic delete_by_query":
setup:
- do:
index:
index: test_1
@ -24,6 +23,8 @@
- do:
indices.refresh: {}
---
"Basic delete_by_query":
- do:
delete_by_query:
index: test_1
@ -40,3 +41,14 @@
index: test_1
- match: { count: 2 }
---
"Delete_by_query body without query element":
- do:
catch: request
delete_by_query:
index: test_1
body:
match:
foo: bar

View File

@ -1,5 +1,4 @@
---
"count with body":
setup:
- do:
indices.create:
index: test
@ -14,6 +13,8 @@
indices.refresh:
index: [test]
---
"count with body":
- do:
count:
index: test
@ -35,3 +36,13 @@
foo: test
- match: {count : 0}
---
"count body without query element":
- do:
catch: request
count:
index: test
body:
match:
foo: bar

View File

@ -1,5 +1,14 @@
---
"Basic explain":
setup:
- do:
indices.create:
index: test_1
body:
aliases:
alias_1: {}
- do:
cluster.health:
wait_for_status: yellow
- do:
index:
index: test_1
@ -10,6 +19,9 @@
- do:
indices.refresh: {}
---
"Basic explain":
- do:
explain:
index: test_1
@ -27,26 +39,6 @@
---
"Basic explain with alias":
- do:
indices.create:
index: test_1
body:
aliases:
alias_1: {}
- do:
cluster.health:
wait_for_status: yellow
- do:
index:
index: test_1
type: test
id: id_1
body: { foo: bar, title: howdy }
- do:
indices.refresh: {}
- do:
explain:
@ -63,3 +55,14 @@
- match: { _type: test }
- match: { _id: id_1 }
---
"Explain body without query element":
- do:
catch: request
explain:
index: test_1
type: test
id: id_1
body:
match_all: {}

View File

@ -1,5 +1,4 @@
---
"Validate query api":
setup:
- do:
indices.create:
index: testing
@ -11,6 +10,8 @@
cluster.health:
wait_for_status: yellow
---
"Validate query api":
- do:
indices.validate_query:
q: query string
@ -34,3 +35,11 @@
- match: {explanations.0.index: 'testing'}
- match: {explanations.0.explanation: '*:*'}
---
"Validate body without query element":
- do:
indices.validate_query:
body:
match_all: {}
- is_false: valid

View File

@ -1,5 +1,4 @@
---
"Default index":
setup:
- do:
indices.create:
index: test_2
@ -24,6 +23,9 @@
indices.refresh:
index: [test_1, test_2]
---
"Basic search":
- do:
search:
index: _all
@ -62,3 +64,14 @@
- match: {hits.hits.0._index: test_2 }
- match: {hits.hits.0._type: test }
- match: {hits.hits.0._id: "42" }
---
"Search body without query element":
- do:
catch: request
search:
body:
match:
foo: bar