Validate query api: move query parsing on the coordinating node

Similarly to what we did with the search api, we can now also move query parsing on the coordinating node for the validate query api. Given that the explain api is a single shard operation (compared to search which is instead a broadcast operation), this doesn't change a lot in how the api works internally. The main benefit is that we can simplify the java api by requiring a structured query object to be provided rather than a bytes array that will get parsed on the data node. Previously if you specified a QueryBuilder it would be serialized in json format and would get reparsed on the data node, while now it doesn't go through parsing anymore (as expected), given that after the query-refactoring we are able to properly stream queries natively. Note that the WrapperQueryBuilder can be used from the java api to provide a query as a string, in that case the actual parsing of the inner query will happen on the data node.

Relates to #10217
Closes #14384
This commit is contained in:
javanna 2015-10-28 19:10:19 +01:00 committed by Luca Cavanna
parent ebec4bdaf6
commit b56bbf62dd
10 changed files with 101 additions and 264 deletions

View File

@ -22,9 +22,9 @@ package org.elasticsearch.action.admin.indices.validate.query;
import org.elasticsearch.action.support.broadcast.BroadcastShardRequest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.shard.ShardId;
import java.io.IOException;
@ -34,7 +34,7 @@ import java.io.IOException;
*/
public class ShardValidateQueryRequest extends BroadcastShardRequest {
private BytesReference source;
private QueryBuilder<?> query;
private String[] types = Strings.EMPTY_ARRAY;
private boolean explain;
private boolean rewrite;
@ -49,7 +49,7 @@ public class ShardValidateQueryRequest extends BroadcastShardRequest {
ShardValidateQueryRequest(ShardId shardId, @Nullable String[] filteringAliases, ValidateQueryRequest request) {
super(shardId, request);
this.source = request.source();
this.query = request.query();
this.types = request.types();
this.explain = request.explain();
this.rewrite = request.rewrite();
@ -57,8 +57,8 @@ public class ShardValidateQueryRequest extends BroadcastShardRequest {
this.nowInMillis = request.nowInMillis;
}
public BytesReference source() {
return source;
public QueryBuilder<?> query() {
return query;
}
public String[] types() {
@ -84,7 +84,7 @@ public class ShardValidateQueryRequest extends BroadcastShardRequest {
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
source = in.readBytesReference();
query = in.readQuery();
int typesSize = in.readVInt();
if (typesSize > 0) {
@ -109,7 +109,7 @@ public class ShardValidateQueryRequest extends BroadcastShardRequest {
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeBytesReference(source);
out.writeQuery(query);
out.writeVInt(types.length);
for (String type : types) {

View File

@ -36,6 +36,7 @@ import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.routing.GroupShardsIterator;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
@ -43,7 +44,6 @@ import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.query.IndexQueryParserService;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.script.ScriptService;
@ -178,9 +178,7 @@ public class TransportValidateQueryAction extends TransportBroadcastAction<Valid
);
SearchContext.setCurrent(searchContext);
try {
if (request.source() != null && request.source().length() > 0) {
searchContext.parsedQuery(queryParserService.parseTopLevelQuery(request.source()));
}
searchContext.parsedQuery(queryParserService.toQuery(request.query()));
searchContext.preProcess();
valid = true;

View File

@ -19,34 +19,27 @@
package org.elasticsearch.action.admin.indices.validate.query;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ValidateActions;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.QuerySourceBuilder;
import org.elasticsearch.action.support.broadcast.BroadcastRequest;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
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.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
/**
* A request to validate a specific query.
* <p>
* The request requires the query source to be set either using {@link #source(QuerySourceBuilder)},
* or {@link #source(byte[])}.
* The request requires the query to be set using {@link #query(QueryBuilder)}
*/
public class ValidateQueryRequest extends BroadcastRequest<ValidateQueryRequest> {
private BytesReference source;
private QueryBuilder<?> query = new MatchAllQueryBuilder();
private boolean explain;
private boolean rewrite;
@ -71,67 +64,21 @@ public class ValidateQueryRequest extends BroadcastRequest<ValidateQueryRequest>
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = super.validate();
if (query == null) {
validationException = ValidateActions.addValidationError("query cannot be null", validationException);
}
return validationException;
}
/**
* The source to execute.
* The query to validate.
*/
public BytesReference source() {
return source;
public QueryBuilder<?> query() {
return query;
}
public ValidateQueryRequest source(QuerySourceBuilder sourceBuilder) {
this.source = sourceBuilder.buildAsBytes(Requests.CONTENT_TYPE);
return this;
}
/**
* The source to execute in the form of a map.
*/
public ValidateQueryRequest source(Map source) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(Requests.CONTENT_TYPE);
builder.map(source);
return source(builder);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
}
public ValidateQueryRequest source(XContentBuilder builder) {
this.source = builder.bytes();
return this;
}
/**
* The query source to validate. It is preferable to use either {@link #source(byte[])}
* or {@link #source(QuerySourceBuilder)}.
*/
public ValidateQueryRequest source(String source) {
this.source = new BytesArray(source);
return this;
}
/**
* The source to validate.
*/
public ValidateQueryRequest source(byte[] source) {
return source(source, 0, source.length);
}
/**
* The source to validate.
*/
public ValidateQueryRequest source(byte[] source, int offset, int length) {
return source(new BytesArray(source, offset, length));
}
/**
* The source to validate.
*/
public ValidateQueryRequest source(BytesReference source) {
this.source = source;
public ValidateQueryRequest query(QueryBuilder<?> query) {
this.query = query;
return this;
}
@ -181,9 +128,7 @@ public class ValidateQueryRequest extends BroadcastRequest<ValidateQueryRequest>
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
source = in.readBytesReference();
query = in.readQuery();
int typesSize = in.readVInt();
if (typesSize > 0) {
types = new String[typesSize];
@ -191,7 +136,6 @@ public class ValidateQueryRequest extends BroadcastRequest<ValidateQueryRequest>
types[i] = in.readString();
}
}
explain = in.readBoolean();
rewrite = in.readBoolean();
}
@ -199,27 +143,18 @@ public class ValidateQueryRequest extends BroadcastRequest<ValidateQueryRequest>
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeBytesReference(source);
out.writeQuery(query);
out.writeVInt(types.length);
for (String type : types) {
out.writeString(type);
}
out.writeBoolean(explain);
out.writeBoolean(rewrite);
}
@Override
public String toString() {
String sSource = "_na_";
try {
sSource = XContentHelper.convertToJson(source, false);
} catch (Exception e) {
// ignore
}
return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", source[" + sSource + "], explain:" + explain +
return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", query[" + query + "], explain:" + explain +
", rewrite:" + rewrite;
}
}

View File

@ -19,10 +19,8 @@
package org.elasticsearch.action.admin.indices.validate.query;
import org.elasticsearch.action.support.QuerySourceBuilder;
import org.elasticsearch.action.support.broadcast.BroadcastOperationRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.index.query.QueryBuilder;
/**
@ -30,8 +28,6 @@ import org.elasticsearch.index.query.QueryBuilder;
*/
public class ValidateQueryRequestBuilder extends BroadcastOperationRequestBuilder<ValidateQueryRequest, ValidateQueryResponse, ValidateQueryRequestBuilder> {
private QuerySourceBuilder sourceBuilder;
public ValidateQueryRequestBuilder(ElasticsearchClient client, ValidateQueryAction action) {
super(client, action, new ValidateQueryRequest());
}
@ -45,32 +41,12 @@ public class ValidateQueryRequestBuilder extends BroadcastOperationRequestBuilde
}
/**
* The query source to validate.
* The query to validate.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
public ValidateQueryRequestBuilder setQuery(QueryBuilder queryBuilder) {
sourceBuilder().setQuery(queryBuilder);
return this;
}
/**
* The source to validate.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
public ValidateQueryRequestBuilder setSource(BytesReference source) {
request().source(source);
return this;
}
/**
* The source to validate.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
public ValidateQueryRequestBuilder setSource(byte[] source) {
request.source(source);
request.query(queryBuilder);
return this;
}
@ -91,19 +67,4 @@ public class ValidateQueryRequestBuilder extends BroadcastOperationRequestBuilde
request.rewrite(rewrite);
return this;
}
@Override
protected ValidateQueryRequest beforeExecute(ValidateQueryRequest request) {
if (sourceBuilder != null) {
request.source(sourceBuilder);
}
return request;
}
private QuerySourceBuilder sourceBuilder() {
if (sourceBuilder == null) {
sourceBuilder = new QuerySourceBuilder();
}
return sourceBuilder;
}
}

View File

@ -1,67 +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.action.support;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilder;
import java.io.IOException;
public class QuerySourceBuilder extends ToXContentToBytes {
private QueryBuilder queryBuilder;
private BytesReference queryBinary;
public QuerySourceBuilder setQuery(QueryBuilder query) {
this.queryBuilder = query;
return this;
}
public QuerySourceBuilder setQuery(BytesReference queryBinary) {
this.queryBinary = queryBinary;
return this;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
innerToXContent(builder, params);
builder.endObject();
return builder;
}
public void innerToXContent(XContentBuilder builder, Params params) throws IOException {
if (queryBuilder != null) {
builder.field("query");
queryBuilder.toXContent(builder, params);
}
if (queryBinary != null) {
if (XContentFactory.xContentType(queryBinary) == builder.contentType()) {
builder.rawField("query", queryBinary);
} else {
builder.field("query_binary", queryBinary);
}
}
}
}

View File

@ -209,30 +209,6 @@ public class IndexQueryParserService extends AbstractIndexComponent {
return indexSettings.getIndexVersionCreated();
}
/**
* Selectively parses a query from a top level query or query_binary json field from the specified source.
*/
public ParsedQuery parseTopLevelQuery(BytesReference source) {
XContentParser parser = null;
try {
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);
}
} catch (ParsingException | QueryShardException e) {
throw e;
} catch (Throwable e) {
throw new ParsingException(parser == null ? null : parser.getTokenLocation(), "Failed to parse", e);
}
}
private ParsedQuery innerParse(QueryShardContext context, XContentParser parser) throws IOException, QueryShardException {
context.reset(parser);
try {

View File

@ -20,9 +20,6 @@
package org.elasticsearch.index.query;
import org.apache.lucene.search.Query;
import java.nio.charset.StandardCharsets;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
@ -32,6 +29,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
@ -110,7 +108,8 @@ public class WrapperQueryBuilder extends AbstractQueryBuilder<WrapperQueryBuilde
try (XContentParser qSourceParser = XContentFactory.xContent(source).createParser(source)) {
final QueryShardContext contextCopy = new QueryShardContext(context.indexQueryParserService());
contextCopy.reset(qSourceParser);
QueryBuilder result = contextCopy.parseContext().parseInnerQueryBuilder();
contextCopy.parseFieldMatcher(context.indexQueryParserService().parseFieldMatcher());
QueryBuilder<?> result = contextCopy.parseContext().parseInnerQueryBuilder();
context.combineNamedQueries(contextCopy);
return result.toQuery(context);
}

View File

@ -23,22 +23,21 @@ import org.elasticsearch.action.admin.indices.validate.query.QueryExplanation;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.QuerySourceBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestActions;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestStatus.OK;
@ -49,8 +48,10 @@ import static org.elasticsearch.rest.action.support.RestActions.buildBroadcastSh
*/
public class RestValidateQueryAction extends BaseRestHandler {
private final IndicesQueriesRegistry indicesQueriesRegistry;
@Inject
public RestValidateQueryAction(Settings settings, RestController controller, Client client) {
public RestValidateQueryAction(Settings settings, RestController controller, Client client, IndicesQueriesRegistry indicesQueriesRegistry) {
super(settings, controller, client);
controller.registerHandler(GET, "/_validate/query", this);
controller.registerHandler(POST, "/_validate/query", this);
@ -58,55 +59,52 @@ public class RestValidateQueryAction extends BaseRestHandler {
controller.registerHandler(POST, "/{index}/_validate/query", this);
controller.registerHandler(GET, "/{index}/{type}/_validate/query", this);
controller.registerHandler(POST, "/{index}/{type}/_validate/query", this);
this.indicesQueriesRegistry = indicesQueriesRegistry;
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) {
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws Exception {
ValidateQueryRequest validateQueryRequest = new ValidateQueryRequest(Strings.splitStringByCommaToArray(request.param("index")));
validateQueryRequest.indicesOptions(IndicesOptions.fromRequest(request, validateQueryRequest.indicesOptions()));
validateQueryRequest.explain(request.paramAsBoolean("explain", false));
if (RestActions.hasBodyContent(request)) {
validateQueryRequest.source(RestActions.getRestContent(request));
try {
validateQueryRequest.query(RestActions.getQueryContent(RestActions.getRestContent(request), indicesQueriesRegistry, parseFieldMatcher));
} catch(ParsingException e) {
channel.sendResponse(buildErrorResponse(channel.newBuilder(), e.getDetailedMessage(), validateQueryRequest.explain()));
return;
} catch(Exception e) {
channel.sendResponse(buildErrorResponse(channel.newBuilder(), e.getMessage(), validateQueryRequest.explain()));
return;
}
} else {
QueryBuilder<?> queryBuilder = RestActions.urlParamsToQueryBuilder(request);
if (queryBuilder != null) {
QuerySourceBuilder querySourceBuilder = new QuerySourceBuilder();
querySourceBuilder.setQuery(queryBuilder);
validateQueryRequest.source(querySourceBuilder);
validateQueryRequest.query(queryBuilder);
}
}
validateQueryRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
if (request.paramAsBoolean("explain", false)) {
validateQueryRequest.explain(true);
} else {
validateQueryRequest.explain(false);
}
if (request.paramAsBoolean("rewrite", false)) {
validateQueryRequest.rewrite(true);
} else {
validateQueryRequest.rewrite(false);
}
validateQueryRequest.rewrite(request.paramAsBoolean("rewrite", false));
client.admin().indices().validateQuery(validateQueryRequest, new RestBuilderListener<ValidateQueryResponse>(channel) {
@Override
public RestResponse buildResponse(ValidateQueryResponse response, XContentBuilder builder) throws Exception {
builder.startObject();
builder.field("valid", response.isValid());
builder.field(VALID_FIELD, response.isValid());
buildBroadcastShardsHeader(builder, request, response);
if (response.getQueryExplanation() != null && !response.getQueryExplanation().isEmpty()) {
builder.startArray("explanations");
builder.startArray(EXPLANATIONS_FIELD);
for (QueryExplanation explanation : response.getQueryExplanation()) {
builder.startObject();
if (explanation.getIndex() != null) {
builder.field("index", explanation.getIndex(), XContentBuilder.FieldCaseConversion.NONE);
builder.field(INDEX_FIELD, explanation.getIndex(), XContentBuilder.FieldCaseConversion.NONE);
}
builder.field("valid", explanation.isValid());
builder.field(VALID_FIELD, explanation.isValid());
if (explanation.getError() != null) {
builder.field("error", explanation.getError());
builder.field(ERROR_FIELD, explanation.getError());
}
if (explanation.getExplanation() != null) {
builder.field("explanation", explanation.getExplanation());
builder.field(EXPLANATION_FIELD, explanation.getExplanation());
}
builder.endObject();
}
@ -117,4 +115,20 @@ public class RestValidateQueryAction extends BaseRestHandler {
}
});
}
private static BytesRestResponse buildErrorResponse(XContentBuilder builder, String error, boolean explain) throws IOException {
builder.startObject();
builder.field(VALID_FIELD, false);
if (explain) {
builder.field(ERROR_FIELD, error);
}
builder.endObject();
return new BytesRestResponse(OK, builder);
}
private static final XContentBuilderString INDEX_FIELD = new XContentBuilderString("index");
private static final XContentBuilderString VALID_FIELD = new XContentBuilderString("valid");
private static final XContentBuilderString EXPLANATIONS_FIELD = new XContentBuilderString("explanations");
private static final XContentBuilderString ERROR_FIELD = new XContentBuilderString("error");
private static final XContentBuilderString EXPLANATION_FIELD = new XContentBuilderString("explanation");
}

View File

@ -66,7 +66,7 @@ public class SimpleValidateQueryIT extends ESIntegTestCase {
refresh();
assertThat(client().admin().indices().prepareValidateQuery("test").setSource("foo".getBytes(StandardCharsets.UTF_8)).execute().actionGet().isValid(), equalTo(false));
assertThat(client().admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.wrapperQuery("foo".getBytes(StandardCharsets.UTF_8))).execute().actionGet().isValid(), equalTo(false));
assertThat(client().admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryStringQuery("_id:1")).execute().actionGet().isValid(), equalTo(true));
assertThat(client().admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryStringQuery("_i:d:1")).execute().actionGet().isValid(), equalTo(false));
@ -94,12 +94,12 @@ public class SimpleValidateQueryIT extends ESIntegTestCase {
for (Client client : internalCluster()) {
ValidateQueryResponse response = client.admin().indices().prepareValidateQuery("test")
.setSource("foo".getBytes(StandardCharsets.UTF_8))
.setQuery(QueryBuilders.wrapperQuery("foo".getBytes(StandardCharsets.UTF_8)))
.setExplain(true)
.execute().actionGet();
assertThat(response.isValid(), equalTo(false));
assertThat(response.getQueryExplanation().size(), equalTo(1));
assertThat(response.getQueryExplanation().get(0).getError(), containsString("Failed to parse"));
assertThat(response.getQueryExplanation().get(0).getError(), containsString("Failed to derive xcontent"));
assertThat(response.getQueryExplanation().get(0).getExplanation(), nullValue());
}
@ -260,7 +260,7 @@ public class SimpleValidateQueryIT extends ESIntegTestCase {
ensureGreen();
refresh();
assertThat(client().admin().indices().prepareValidateQuery("test").setSource(new BytesArray("{\"foo\": \"bar\", \"query\": {\"term\" : { \"user\" : \"kimchy\" }}}")).get().isValid(), equalTo(false));
assertThat(client().admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.wrapperQuery(new BytesArray("{\"foo\": \"bar\", \"query\": {\"term\" : { \"user\" : \"kimchy\" }}}"))).get().isValid(), equalTo(false));
}
public void testIrrelevantPropertiesAfterQuery() throws IOException {
@ -268,7 +268,7 @@ public class SimpleValidateQueryIT extends ESIntegTestCase {
ensureGreen();
refresh();
assertThat(client().admin().indices().prepareValidateQuery("test").setSource(new BytesArray("{\"query\": {\"term\" : { \"user\" : \"kimchy\" }}, \"foo\": \"bar\"}")).get().isValid(), equalTo(false));
assertThat(client().admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.wrapperQuery(new BytesArray("{\"query\": {\"term\" : { \"user\" : \"kimchy\" }}, \"foo\": \"bar\"}"))).get().isValid(), equalTo(false));
}
private static void assertExplanation(QueryBuilder queryBuilder, Matcher<String> matcher, boolean withRewrite) {

View File

@ -25,6 +25,17 @@ setup:
invalid_query: {}
- is_false: valid
- is_false: error
- do:
indices.validate_query:
explain: true
body:
query:
invalid_query: {}
- is_false: valid
- match: {error: 'org.elasticsearch.common.ParsingException: No query registered for [invalid_query]'}
- do:
indices.validate_query:
@ -43,3 +54,13 @@ setup:
match_all: {}
- is_false: valid
- is_false: error
- do:
indices.validate_query:
explain: true
body:
match_all: {}
- is_false: valid
- match: {error: 'org.elasticsearch.common.ParsingException: request does not support [match_all]'}