From 6a6b61f9c97b5574bf6f7bc86ac84033ccd80e99 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Mon, 4 Jun 2018 16:45:35 +0200 Subject: [PATCH 1/7] added validate query API Relates to #27205 --- .../elasticsearch/client/IndicesClient.java | 25 ++++ .../client/RequestConverters.java | 12 ++ .../elasticsearch/client/IndicesClientIT.java | 39 ++++++ .../IndicesClientDocumentationIT.java | 83 +++++++++++++ .../indices/validate_query.asciidoc | 112 +++++++++++++++++ .../high-level/supported-apis.asciidoc | 2 + .../validate/query/QueryExplanation.java | 114 +++++++++++++++++- .../validate/query/ValidateQueryRequest.java | 11 +- .../validate/query/ValidateQueryResponse.java | 101 +++++++++++++--- .../indices/RestValidateQueryAction.java | 3 +- .../validate/query/QueryExplanationTests.java | 59 +++++++++ .../query/ValidateQueryResponseTests.java | 83 +++++++++++++ .../AbstractStreamableXContentTestCase.java | 11 +- 13 files changed, 634 insertions(+), 21 deletions(-) create mode 100644 docs/java-rest/high-level/indices/validate_query.asciidoc create mode 100644 server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanationTests.java create mode 100644 server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index fa7eb9ab9ec8a..a344712831ce6 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -56,6 +56,8 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse; import java.io.IOException; import java.util.Collections; @@ -1059,4 +1061,27 @@ public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest, Re restHighLevelClient.performRequestAsyncAndParseEntity(putIndexTemplateRequest, RequestConverters::putTemplate, options, PutIndexTemplateResponse::fromXContent, listener, emptySet()); } + + /** + * Validate a potentially expensive query without executing it. + *

+ * See Validate Query API + * on elastic.co + */ + public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, + ValidateQueryResponse::fromXContent, emptySet(), headers); + } + + /** + * Asynchronously validate a potentially expensive query without executing it. + *

+ * See Validate Query API + * on elastic.co + */ + public void validateQueryAsync(ValidateQueryRequest validateQueryRequest, + ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, + ValidateQueryResponse::fromXContent, listener, emptySet(), headers); + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index b061289888c0c..09ed606ba7699 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -55,6 +55,7 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest; @@ -818,6 +819,17 @@ static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) thro return request; } + static Request validateQuery(ValidateQueryRequest validateQueryRequest) throws IOException { + String endpoint = endpoint(validateQueryRequest.indices(), validateQueryRequest.types(),"_validate/query"); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + Params params = new Params(request); + params.putParam("explain", Boolean.toString(validateQueryRequest.explain())); + params.putParam("all_shards", Boolean.toString(validateQueryRequest.allShards())); + params.putParam("rewrite", Boolean.toString(validateQueryRequest.rewrite())); + request.setEntity(createEntity(validateQueryRequest, REQUEST_BODY_CONTENT_TYPE)); + return request; + } + private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef(); return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType)); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index 986c3380ff3c8..6fb238dee0080 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -20,6 +20,7 @@ package org.elasticsearch.client; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchStatusException; @@ -61,6 +62,8 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.WriteRequest; @@ -76,6 +79,8 @@ import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.index.IndexSettings; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; import java.io.IOException; @@ -1002,4 +1007,38 @@ public void testPutTemplateBadRequests() throws Exception { () -> execute(unknownSettingTemplate, client.indices()::putTemplate, client.indices()::putTemplateAsync)); assertThat(unknownSettingError.getDetailedMessage(), containsString("unknown setting [index.this-setting-does-not-exist]")); } + + public void testValidateQuery() throws IOException{ + String index = "some_index"; + createIndex(index, Settings.EMPTY); + QueryBuilder builder = QueryBuilders + .boolQuery() + .must(QueryBuilders.queryStringQuery("*:*")) + .filter(QueryBuilders.termQuery("user", "kimchy")); + ValidateQueryRequest request = new ValidateQueryRequest(index).query(builder); + request.explain(randomBoolean()); + ValidateQueryResponse response = execute(request, highLevelClient().indices()::validateQuery, + highLevelClient().indices()::validateQueryAsync); + assertTrue(response.isValid()); + } + + public void testInvalidValidateQuery() throws IOException{ + String index = "shakespeare"; + + createIndex(index, Settings.EMPTY); + Request postDoc = new Request(HttpPost.METHOD_NAME, "/" + index + "/1"); + postDoc.setJsonEntity( + "{\"type\":\"act\",\"line_id\":1,\"play_name\":\"Henry IV\", \"speech_number\":\"\"," + + "\"line_number\":\"\",\"speaker\":\"\",\"text_entry\":\"ACT I\"}"); + assertOK(client().performRequest(postDoc)); + + QueryBuilder builder = QueryBuilders + .queryStringQuery("line_id:foo") + .lenient(false); + ValidateQueryRequest request = new ValidateQueryRequest(index).query(builder); + request.explain(true); + ValidateQueryResponse response = execute(request, highLevelClient().indices()::validateQuery, + highLevelClient().indices()::validateQueryAsync); + assertFalse(response.isValid()); + } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 2b81e4a4adce9..91b73974151cc 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -60,6 +60,9 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +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.ActiveShardCount; import org.elasticsearch.action.support.DefaultShardOperationFailedException; import org.elasticsearch.action.support.IndicesOptions; @@ -76,12 +79,14 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; import java.io.IOException; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -1983,4 +1988,82 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } + + public void testValidateQuery() throws IOException, InterruptedException { + RestHighLevelClient client = highLevelClient(); + + String index = "some_index"; + createIndex(index, Settings.EMPTY); + + // tag::validate-query-request + ValidateQueryRequest request = new ValidateQueryRequest(index); // <1> + // end::validate-query-request + + // tag::validate-query-request-query + QueryBuilder builder = QueryBuilders + .boolQuery() // <1> + .must(QueryBuilders.queryStringQuery("*:*")) + .filter(QueryBuilders.termQuery("user", "kimchy")); + // end::validate-query-request-query + + // tag::validate-query-request-explain + request.explain(true); // <1> + // end::validate-query-request-explain + + // tag::validate-query-request-allShards + request.allShards(true); // <1> + // end::validate-query-request-allShards + + // tag::validate-query-request-rewrite + request.rewrite(true); // <1> + // end::validate-query-request-rewrite + + // tag::validate-query-execute + ValidateQueryResponse response = client.indices().validateQuery(request); // <1> + // end::validate-query-execute + + // tag::validate-query-response + boolean isValid = response.isValid(); // <1> + int totalShards = response.getTotalShards(); // <2> + int successfulShards = response.getSuccessfulShards(); // <3> + int failedShards = response.getFailedShards(); // <4> + if (failedShards > 0) { + for(DefaultShardOperationFailedException failure: response.getShardFailures()) { // <5> + String failedIndex = failure.index(); // <6> + int shardId = failure.shardId(); // <7> + String reason = failure.reason(); // <8> + } + } + for(QueryExplanation explanation: response.getQueryExplanation()) { // <9> + String explanationIndex = explanation.getIndex(); // <10> + int shardId = explanation.getShard(); // <11> + String explanationString = explanation.getExplanation(); // <12> + } + // end::validate-query-response + + // tag::validate-query-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(ValidateQueryResponse validateQueryResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::validate-query-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::validate-query-execute-async + client.indices().validateQueryAsync(request, listener); // <1> + // end::validate-query-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } } diff --git a/docs/java-rest/high-level/indices/validate_query.asciidoc b/docs/java-rest/high-level/indices/validate_query.asciidoc new file mode 100644 index 0000000000000..334cf7881a2de --- /dev/null +++ b/docs/java-rest/high-level/indices/validate_query.asciidoc @@ -0,0 +1,112 @@ +[[java-rest-high-indices-validate-query]] +=== Validate Query API + +[[java-rest-high-indices-validate-query-request]] +==== Validate Query Request + +A `ValidateRequest` requires one or more `indices` on which to the query is validated. If not index +is provided the request is executed on all indices. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request] +-------------------------------------------------- +<1> The index on which to run the request. + +In addition it also needs the query that needs to be validated. The query can be built using the `QueryBuilders` utility class. +The following code snippet builds a sample boolean query. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request-query] +-------------------------------------------------- +<1> Build the desired query. + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request-explain] +-------------------------------------------------- +<1> The explain parameter can be set to true to get more detailed information about why a query failed + +By default, the request is executed on a single shard only, which is randomly selected. The detailed explanation of +the query may depend on which shard is being hit, and therefore may vary from one request to another. So, in case of +query rewrite the `allShards` parameter should be used to get response from all available shards. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request-allShards] +-------------------------------------------------- +<1> Set the allShards parameter. + +When the query is valid, the explanation defaults to the string representation of that query. With rewrite set to true, +the explanation is more detailed showing the actual Lucene query that will be executed + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request-rewrite] +-------------------------------------------------- +<1> Set the rewrite parameter. + +[[java-rest-high-indices-validate-query-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-execute] +-------------------------------------------------- +<1> Execute the request and get back the response in a ValidateQueryResponse object. + +[[java-rest-high-indices-validate-query-async]] +==== Asynchronous Execution + +The asynchronous execution of a validate query request requires both the `ValidateQueryRequest` +instance and an `ActionListener` instance to be passed to the asynchronous +method: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-execute-async] +-------------------------------------------------- +<1> The `ValidateQueryRequest` to execute and the `ActionListener` to use when +the execution completes + +The asynchronous method does not block and returns immediately. Once it is +completed the `ActionListener` is called back using the `onResponse` method +if the execution successfully completed or using the `onFailure` method if +it failed. + +A typical listener for `ValidateQueryResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-execute-listener] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument + +[[java-rest-high-indices-validate-query-response]] +==== Validate Query Response + +The returned `ValidateQueryResponse` allows to retrieve information about the executed + operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-response] +-------------------------------------------------- +<1> Check if the query is valid or not. +<2> Get total number of shards. +<3> Get number of shards that were successful. +<4> Get number of shards that failed. +<5> Get the shard failures as `DefaultShardOperationFailedException`. +<6> Get the index of a failed shard. +<7> Get the shard id of a failed shard. +<8> Get the reason for shard failure. +<9> Get the detailed explanation for the shards (if explain was set to `true`). +<10> Get the index to which a particular explanation belongs. +<11> Get the shard id to which a particular explanation belongs. +<12> Get the actual explanation string. \ No newline at end of file diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 34149bee52880..49bc9988a665d 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -73,6 +73,7 @@ Index Management:: * <> * <> * <> +* <> Mapping Management:: * <> @@ -101,6 +102,7 @@ include::indices/exists_alias.asciidoc[] include::indices/put_settings.asciidoc[] include::indices/get_settings.asciidoc[] include::indices/put_template.asciidoc[] +include::indices/validate_query.asciidoc[] == Cluster APIs diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java index 780bf037f0e28..1de90cee86c23 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java @@ -20,16 +20,59 @@ package org.elasticsearch.action.admin.indices.validate.query; import org.elasticsearch.Version; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import java.util.Map; -public class QueryExplanation implements Streamable { +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg; + +public class QueryExplanation implements Streamable, ToXContentFragment { + + public static final String INDEX_FIELD = "index"; + public static final String SHARD_FIELD = "shard"; + public static final String VALID_FIELD = "valid"; + public static final String ERROR_FIELD = "error"; + public static final String EXPLANATION_FIELD = "explanation"; public static final int RANDOM_SHARD = -1; + @SuppressWarnings("unchecked") + static ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "query_explanation", + true, + a -> { + int shard = RANDOM_SHARD; + if (a[1] != null) { + shard = (int)a[1]; + } + return new QueryExplanation( + (String)a[0], + shard, + (boolean)a[2], + (String)a[3], + (String)a[4] + ); + } + ); + static { + PARSER.declareString(optionalConstructorArg(), new ParseField(INDEX_FIELD)); + PARSER.declareInt(optionalConstructorArg(), new ParseField(SHARD_FIELD)); + PARSER.declareBoolean(constructorArg(), new ParseField(VALID_FIELD)); + PARSER.declareString(optionalConstructorArg(), new ParseField(EXPLANATION_FIELD)); + PARSER.declareString(optionalConstructorArg(), new ParseField(ERROR_FIELD)); + } + + + private String index; private int shard = RANDOM_SHARD; @@ -110,4 +153,73 @@ public static QueryExplanation readQueryExplanation(StreamInput in) throws IOEx exp.readFrom(in); return exp; } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + if (getIndex() != null) { + builder.field(INDEX_FIELD, getIndex()); + } + if(getShard() >= 0) { + builder.field(SHARD_FIELD, getShard()); + } + builder.field(VALID_FIELD, isValid()); + if (getError() != null) { + builder.field(ERROR_FIELD, getError()); + } + if (getExplanation() != null) { + builder.field(EXPLANATION_FIELD, getExplanation()); + } + return builder; + } + + public static QueryExplanation fromXContent(XContentParser parser) { + return PARSER.apply(parser, null); + } + + @Override + public boolean equals(Object o) { + if (o instanceof QueryExplanation) { + QueryExplanation other = (QueryExplanation) o; + boolean result; + if (getIndex() == null) { + result = other.getIndex() == null; + } else { + result = getIndex().equals(other.getIndex()); + } + result &= this.getShard() == other.getShard(); + result &= isValid() == other.isValid(); + if (getError() == null) { + result &= other.getError() == null; + } else { + result &= getError().equals(other.getError()); + } + if (getExplanation() == null) { + result &= other.getExplanation() == null; + } else { + result &= getExplanation().equals(other.getExplanation()); + } + return result; + } else { + return false; + } + } + + @Override + public int hashCode() { + int result = 1; + if (getIndex() != null) { + result = 31 * result + getIndex().hashCode(); + } + if(getShard() >= 0) { + result = 31 * result + getShard(); + } + result = 31 * result + (isValid() ? 1 : 0); + if (getError() != null) { + result = 31 * result + getError().hashCode(); + } + if (getExplanation() != null) { + result = 31 * result + getExplanation().hashCode(); + } + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java index 5953a5548c465..f4baffb4af904 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java @@ -27,6 +27,8 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; @@ -38,7 +40,7 @@ *

* The request requires the query to be set using {@link #query(QueryBuilder)} */ -public class ValidateQueryRequest extends BroadcastRequest { +public class ValidateQueryRequest extends BroadcastRequest implements ToXContentFragment { private QueryBuilder query = new MatchAllQueryBuilder(); @@ -179,4 +181,11 @@ public String toString() { return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", query[" + query + "], explain:" + explain + ", rewrite:" + rewrite + ", all_shards:" + allShards; } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.field("query"); + query.toXContent(builder, params); + return builder; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java index 5bb11dd56e00b..30802ebe9a6f2 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java @@ -21,16 +21,26 @@ import org.elasticsearch.action.support.DefaultShardOperationFailedException; import org.elasticsearch.action.support.broadcast.BroadcastResponse; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import static org.elasticsearch.action.admin.indices.validate.query.QueryExplanation.readQueryExplanation; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg; /** * The response of the validate action. @@ -39,12 +49,33 @@ */ public class ValidateQueryResponse extends BroadcastResponse { - public static final String INDEX_FIELD = "index"; - public static final String SHARD_FIELD = "shard"; public static final String VALID_FIELD = "valid"; public static final String EXPLANATIONS_FIELD = "explanations"; - public static final String ERROR_FIELD = "error"; - public static final String EXPLANATION_FIELD = "explanation"; + + @SuppressWarnings("unchecked") + static ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "validate_query", + true, + arg -> { + BroadcastResponse response = (BroadcastResponse) arg[0]; + return + new ValidateQueryResponse( + (boolean)arg[1], + (List)arg[2], + response.getTotalShards(), + response.getSuccessfulShards(), + response.getFailedShards(), + Arrays.asList(response.getShardFailures()) + ); + } + ); + static { + declareBroadcastFields(PARSER); + PARSER.declareBoolean(constructorArg(), new ParseField(VALID_FIELD)); + PARSER.declareObjectArray( + optionalConstructorArg(), QueryExplanation.PARSER, new ParseField(EXPLANATIONS_FIELD) + ); + } private boolean valid; @@ -112,22 +143,58 @@ protected void addCustomXContentFields(XContentBuilder builder, Params params) t builder.startArray(EXPLANATIONS_FIELD); for (QueryExplanation explanation : getQueryExplanation()) { builder.startObject(); - if (explanation.getIndex() != null) { - builder.field(INDEX_FIELD, explanation.getIndex()); - } - if(explanation.getShard() >= 0) { - builder.field(SHARD_FIELD, explanation.getShard()); - } - builder.field(VALID_FIELD, explanation.isValid()); - if (explanation.getError() != null) { - builder.field(ERROR_FIELD, explanation.getError()); - } - if (explanation.getExplanation() != null) { - builder.field(EXPLANATION_FIELD, explanation.getExplanation()); - } + explanation.toXContent(builder, params); builder.endObject(); } builder.endArray(); } } + + public static ValidateQueryResponse fromXContent(XContentParser parser) { + return PARSER.apply(parser, null); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ValidateQueryResponse) { + ValidateQueryResponse other = (ValidateQueryResponse) o; + Set queryExplSet = new HashSet<>(getQueryExplanation()); + // We only compare with the index and the shardId because for every failure this is unique. + // Also because it is hard to compare Throwable. + Set> shardFailureSet = + Arrays.stream(getShardFailures()) + .map(sF -> new Tuple<>(sF.index(), sF.shardId())).collect(Collectors.toSet()); + return + valid == other.valid && + this.getTotalShards() == other.getTotalShards() && + this.getSuccessfulShards() == other.getSuccessfulShards() && + this.getFailedShards() == other.getFailedShards() && + this.getQueryExplanation().size() == other.getQueryExplanation().size() && + this.getShardFailures().length == other.getShardFailures().length && + queryExplSet.containsAll(other.getQueryExplanation()) && + Arrays.stream(other.getShardFailures()).allMatch( + sF -> shardFailureSet.contains(new Tuple<>(sF.index(), sF.shardId())) + ); + } else { + return false; + } + } + + @Override + public int hashCode() { + int result = isValid() ? 1 : 0; + result = 31 * result + getTotalShards(); + result = 31 * result + getSuccessfulShards(); + result = 31 * result + getFailedShards(); + // Order does not matter + for (QueryExplanation qE: getQueryExplanation()) { + result += qE.hashCode(); + } + // Order does not matter + for (DefaultShardOperationFailedException defaultFailure: getShardFailures()) { + int indexHash = defaultFailure.index() != null ? defaultFailure.index().hashCode() : 0; + result += (31 * indexHash) + defaultFailure.shardId(); + } + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestValidateQueryAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestValidateQueryAction.java index 57486396f911b..d1a97d74d047f 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestValidateQueryAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestValidateQueryAction.java @@ -19,6 +19,7 @@ package org.elasticsearch.rest.action.admin.indices; +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; @@ -101,7 +102,7 @@ private static BytesRestResponse buildErrorResponse(XContentBuilder builder, Str builder.startObject(); builder.field(ValidateQueryResponse.VALID_FIELD, false); if (explain) { - builder.field(ValidateQueryResponse.ERROR_FIELD, error); + builder.field(QueryExplanation.ERROR_FIELD, error); } builder.endObject(); return new BytesRestResponse(OK, builder); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanationTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanationTests.java new file mode 100644 index 0000000000000..db167e0c7669e --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanationTests.java @@ -0,0 +1,59 @@ +/* + * 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.admin.indices.validate.query; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractStreamableXContentTestCase; + +import java.io.IOException; + +public class QueryExplanationTests extends AbstractStreamableXContentTestCase { + + static QueryExplanation createRandomQueryExplanation(boolean isValid) { + String index = "index_" + randomInt(1000); + int shard = randomInt(100); + Boolean valid = isValid; + String errorField = null; + if (!valid) { + errorField = randomAlphaOfLength(randomIntBetween(10, 100)); + } + String explanation = randomAlphaOfLength(randomIntBetween(10, 100)); + return new QueryExplanation(index, shard, valid, explanation, errorField); + } + + static QueryExplanation createRandomQueryExplanation() { + return createRandomQueryExplanation(randomBoolean()); + } + + @Override + protected QueryExplanation doParseInstance(XContentParser parser) throws IOException { + return QueryExplanation.fromXContent(parser); + } + + @Override + protected QueryExplanation createBlankInstance() { + return new QueryExplanation(); + } + + @Override + protected QueryExplanation createTestInstance() { + return createRandomQueryExplanation(); + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java new file mode 100644 index 0000000000000..f250ccd3594f0 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java @@ -0,0 +1,83 @@ +/* + * 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.admin.indices.validate.query; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.support.DefaultShardOperationFailedException; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractStreamableXContentTestCase; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ValidateQueryResponseTests extends AbstractStreamableXContentTestCase { + + @Override + protected boolean assertToXContentEquivalence() { + // We cannot have XContent equivalence for ValidateResponseTests as it holds the BroadcastResponse which + // holds a List. The DefaultShardOperationFailedException uses ElasticSearchException + // for serializing/deserializing a Throwable and the serialized and deserialized versions do not match. + return false; + } + + protected static ValidateQueryResponse createRandomValidateQueryResponse() { + int totalShards = randomIntBetween(1, 10); + int successfulShards = randomIntBetween(0, totalShards); + int failedShards = totalShards - successfulShards; + boolean valid = failedShards == 0; + List queryExplanations = new ArrayList<>(totalShards); + List shardFailures = new ArrayList<>(failedShards); + for (int i=0; i Date: Tue, 5 Jun 2018 13:19:26 +0200 Subject: [PATCH 2/7] Fixes for review -- Removed equals and hashCode from ValidateQueryResponse -- Extended AbstractBroadcastResponseTestCase instead of AbstractStreamableXContentTestCase -- Fixed asciidoc -- Added test for RequestConverters::validateQuery -- Added indicesOptions --- .../client/RequestConverters.java | 5 +- .../client/RequestConvertersTests.java | 39 +++++++++++- .../indices/validate_query.asciidoc | 2 +- .../validate/query/QueryExplanation.java | 60 +++++++------------ .../validate/query/ValidateQueryResponse.java | 48 --------------- .../query/ValidateQueryResponseTests.java | 51 ++++++++++++---- 6 files changed, 104 insertions(+), 101 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index 09ed606ba7699..d70f3ffd4f956 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -820,9 +820,12 @@ static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) thro } static Request validateQuery(ValidateQueryRequest validateQueryRequest) throws IOException { - String endpoint = endpoint(validateQueryRequest.indices(), validateQueryRequest.types(),"_validate/query"); + String[] indices = validateQueryRequest.indices() == null ? Strings.EMPTY_ARRAY : validateQueryRequest.indices(); + String[] types = validateQueryRequest.types() == null || indices.length <= 0 ? Strings.EMPTY_ARRAY : validateQueryRequest.types(); + String endpoint = endpoint(indices, types, "_validate/query"); Request request = new Request(HttpGet.METHOD_NAME, endpoint); Params params = new Params(request); + params.withIndicesOptions(validateQueryRequest.indicesOptions()); params.putParam("explain", Boolean.toString(validateQueryRequest.explain())); params.putParam("all_shards", Boolean.toString(validateQueryRequest.allShards())); params.putParam("rewrite", Boolean.toString(validateQueryRequest.rewrite())); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index ee372e255e70a..de22f82f0d9d6 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -57,6 +57,7 @@ import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; +import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -705,8 +706,8 @@ public void testSyncedFlush() { Request request = RequestConverters.flushSynced(syncedFlushRequest); StringJoiner endpoint = new StringJoiner("/", "/", ""); if (indices != null && indices.length > 0) { - endpoint.add(String.join(",", indices)); - } + endpoint.add(String.join(",", indices)); + } endpoint.add("_flush/synced"); assertThat(request.getEndpoint(), equalTo(endpoint.toString())); assertThat(request.getParameters(), equalTo(expectedParams)); @@ -1762,6 +1763,40 @@ public void testPutTemplateRequest() throws Exception { assertToXContentBody(putTemplateRequest, request.getEntity()); } + public void testValidateQuery() throws Exception { + String[] indices = randomBoolean() ? null : randomIndicesNames(0, 5); + String[] types = randomBoolean() ? generateRandomStringArray(5, 5, false, false): null; + ValidateQueryRequest validateQueryRequest; + if (randomBoolean()) { + validateQueryRequest = new ValidateQueryRequest(indices); + } else { + validateQueryRequest = new ValidateQueryRequest(); + validateQueryRequest.indices(indices); + } + validateQueryRequest.types(types); + Map expectedParams = new HashMap<>(); + setRandomIndicesOptions(validateQueryRequest::indicesOptions, validateQueryRequest::indicesOptions, expectedParams); + validateQueryRequest.explain(randomBoolean()); + validateQueryRequest.rewrite(randomBoolean()); + validateQueryRequest.allShards(randomBoolean()); + expectedParams.put("explain", Boolean.toString(validateQueryRequest.explain())); + expectedParams.put("rewrite", Boolean.toString(validateQueryRequest.rewrite())); + expectedParams.put("all_shards", Boolean.toString(validateQueryRequest.allShards())); + Request request = RequestConverters.validateQuery(validateQueryRequest); + StringJoiner endpoint = new StringJoiner("/", "/", ""); + if (indices != null && indices.length > 0) { + endpoint.add(String.join(",", indices)); + if (types != null && types.length > 0) { + endpoint.add(String.join(",", types)); + } + } + endpoint.add("_validate/query"); + assertThat(request.getEndpoint(), equalTo(endpoint.toString())); + assertThat(request.getParameters(), equalTo(expectedParams)); + assertToXContentBody(validateQueryRequest, request.getEntity()); + assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME)); + } + private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException { BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false); assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue()); diff --git a/docs/java-rest/high-level/indices/validate_query.asciidoc b/docs/java-rest/high-level/indices/validate_query.asciidoc index 334cf7881a2de..2946bb05e9f36 100644 --- a/docs/java-rest/high-level/indices/validate_query.asciidoc +++ b/docs/java-rest/high-level/indices/validate_query.asciidoc @@ -4,7 +4,7 @@ [[java-rest-high-indices-validate-query-request]] ==== Validate Query Request -A `ValidateRequest` requires one or more `indices` on which to the query is validated. If not index +A `ValidateQueryRequest` requires one or more `indices` on which the query is validated. If no index is provided the request is executed on all indices. ["source","java",subs="attributes,callouts,macros"] diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java index 1de90cee86c23..620f4d6319f69 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java @@ -30,7 +30,7 @@ import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; -import java.util.Map; +import java.util.Objects; import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg; @@ -178,48 +178,32 @@ public static QueryExplanation fromXContent(XContentParser parser) { @Override public boolean equals(Object o) { - if (o instanceof QueryExplanation) { - QueryExplanation other = (QueryExplanation) o; - boolean result; - if (getIndex() == null) { - result = other.getIndex() == null; - } else { - result = getIndex().equals(other.getIndex()); - } - result &= this.getShard() == other.getShard(); - result &= isValid() == other.isValid(); - if (getError() == null) { - result &= other.getError() == null; - } else { - result &= getError().equals(other.getError()); - } - if (getExplanation() == null) { - result &= other.getExplanation() == null; - } else { - result &= getExplanation().equals(other.getExplanation()); - } - return result; + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + QueryExplanation other = (QueryExplanation) o; + boolean result; + if (getIndex() == null) { + result = other.getIndex() == null; + } else { + result = getIndex().equals(other.getIndex()); + } + result &= this.getShard() == other.getShard(); + result &= isValid() == other.isValid(); + if (getError() == null) { + result &= other.getError() == null; } else { - return false; + result &= getError().equals(other.getError()); } + if (getExplanation() == null) { + result &= other.getExplanation() == null; + } else { + result &= getExplanation().equals(other.getExplanation()); + } + return result; } @Override public int hashCode() { - int result = 1; - if (getIndex() != null) { - result = 31 * result + getIndex().hashCode(); - } - if(getShard() >= 0) { - result = 31 * result + getShard(); - } - result = 31 * result + (isValid() ? 1 : 0); - if (getError() != null) { - result = 31 * result + getError().hashCode(); - } - if (getExplanation() != null) { - result = 31 * result + getExplanation().hashCode(); - } - return result; + return Objects.hash(getIndex(), getShard(), isValid(), getError(), getExplanation()); } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java index 30802ebe9a6f2..f766e1d9c6aa4 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponse.java @@ -22,7 +22,6 @@ import org.elasticsearch.action.support.DefaultShardOperationFailedException; import org.elasticsearch.action.support.broadcast.BroadcastResponse; import org.elasticsearch.common.ParseField; -import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ConstructingObjectParser; @@ -33,10 +32,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; import static org.elasticsearch.action.admin.indices.validate.query.QueryExplanation.readQueryExplanation; import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; @@ -153,48 +149,4 @@ protected void addCustomXContentFields(XContentBuilder builder, Params params) t public static ValidateQueryResponse fromXContent(XContentParser parser) { return PARSER.apply(parser, null); } - - @Override - public boolean equals(Object o) { - if (o instanceof ValidateQueryResponse) { - ValidateQueryResponse other = (ValidateQueryResponse) o; - Set queryExplSet = new HashSet<>(getQueryExplanation()); - // We only compare with the index and the shardId because for every failure this is unique. - // Also because it is hard to compare Throwable. - Set> shardFailureSet = - Arrays.stream(getShardFailures()) - .map(sF -> new Tuple<>(sF.index(), sF.shardId())).collect(Collectors.toSet()); - return - valid == other.valid && - this.getTotalShards() == other.getTotalShards() && - this.getSuccessfulShards() == other.getSuccessfulShards() && - this.getFailedShards() == other.getFailedShards() && - this.getQueryExplanation().size() == other.getQueryExplanation().size() && - this.getShardFailures().length == other.getShardFailures().length && - queryExplSet.containsAll(other.getQueryExplanation()) && - Arrays.stream(other.getShardFailures()).allMatch( - sF -> shardFailureSet.contains(new Tuple<>(sF.index(), sF.shardId())) - ); - } else { - return false; - } - } - - @Override - public int hashCode() { - int result = isValid() ? 1 : 0; - result = 31 * result + getTotalShards(); - result = 31 * result + getSuccessfulShards(); - result = 31 * result + getFailedShards(); - // Order does not matter - for (QueryExplanation qE: getQueryExplanation()) { - result += qE.hashCode(); - } - // Order does not matter - for (DefaultShardOperationFailedException defaultFailure: getShardFailures()) { - int indexHash = defaultFailure.index() != null ? defaultFailure.index().hashCode() : 0; - result += (31 * indexHash) + defaultFailure.shardId(); - } - return result; - } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java index f250ccd3594f0..b523e25bb379b 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java @@ -21,22 +21,34 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.support.DefaultShardOperationFailedException; +import org.elasticsearch.action.support.broadcast.AbstractBroadcastResponseTestCase; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.AbstractStreamableXContentTestCase; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; -public class ValidateQueryResponseTests extends AbstractStreamableXContentTestCase { +public class ValidateQueryResponseTests extends AbstractBroadcastResponseTestCase { - @Override - protected boolean assertToXContentEquivalence() { - // We cannot have XContent equivalence for ValidateResponseTests as it holds the BroadcastResponse which - // holds a List. The DefaultShardOperationFailedException uses ElasticSearchException - // for serializing/deserializing a Throwable and the serialized and deserialized versions do not match. - return false; + protected static ValidateQueryResponse createRandomValidateQueryResponse( + int totalShards, int successfulShards, int failedShards, List failures) { + boolean valid = failedShards == 0; + List queryExplanations = new ArrayList<>(totalShards); + for(DefaultShardOperationFailedException failure: failures) { + queryExplanations.add( + new QueryExplanation( + failure.index(), failure.shardId(), false, failure.reason(), null + ) + ); + } + return new ValidateQueryResponse( + valid, queryExplanations, totalShards, successfulShards, failedShards, failures + ); } protected static ValidateQueryResponse createRandomValidateQueryResponse() { @@ -72,12 +84,29 @@ protected ValidateQueryResponse doParseInstance(XContentParser parser) throws IO } @Override - protected ValidateQueryResponse createBlankInstance() { - return new ValidateQueryResponse(); + protected ValidateQueryResponse createTestInstance() { + return createRandomValidateQueryResponse(); + } + + @Override + protected void assertEqualInstances(ValidateQueryResponse response, ValidateQueryResponse parsedResponse) { + super.assertEqualInstances(response, parsedResponse); + Set queryExplSet = new HashSet<>(response.getQueryExplanation()); + assertEquals(response.isValid(), parsedResponse.isValid()); + assertEquals(response.getQueryExplanation().size(), parsedResponse.getQueryExplanation().size()); + assertTrue(queryExplSet.containsAll(parsedResponse.getQueryExplanation())); } @Override - protected ValidateQueryResponse createTestInstance() { - return createRandomValidateQueryResponse(); + protected ValidateQueryResponse createTestInstance(int totalShards, int successfulShards, int failedShards, + List failures) { + return createRandomValidateQueryResponse(totalShards, successfulShards, failedShards, failures); + } + + @Override + public void testToXContent() { + ValidateQueryResponse response = createTestInstance(10, 10, 0, new ArrayList<>()); + String output = Strings.toString(response); + assertEquals("{\"_shards\":{\"total\":10,\"successful\":10,\"failed\":0},\"valid\":true}", output); } } From 7bcc283a8983d4b9314a620de2d515ad7ab6b49b Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Tue, 5 Jun 2018 13:43:04 +0200 Subject: [PATCH 3/7] removed changes to AbstractStreamableXContentTestCase.java --- .../test/AbstractStreamableXContentTestCase.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java index 0ec040fadb134..0c165f92e3998 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractStreamableXContentTestCase.java @@ -35,7 +35,7 @@ public abstract class AbstractStreamableXContentTestCase Date: Thu, 7 Jun 2018 14:49:24 +0200 Subject: [PATCH 4/7] switched to RequestOptions from Headers --- .../org/elasticsearch/client/IndicesClient.java | 14 +++++++------- .../IndicesClientDocumentationIT.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index a344712831ce6..5bb2f2ea04ca8 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -1068,9 +1068,9 @@ public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest, Re * See Validate Query API * on elastic.co */ - public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryRequest, Header... headers) throws IOException { - return restHighLevelClient.performRequestAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, - ValidateQueryResponse::fromXContent, emptySet(), headers); + public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryRequest, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, options, + ValidateQueryResponse::fromXContent, emptySet()); } /** @@ -1079,9 +1079,9 @@ public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryReq * See Validate Query API * on elastic.co */ - public void validateQueryAsync(ValidateQueryRequest validateQueryRequest, - ActionListener listener, Header... headers) { - restHighLevelClient.performRequestAsyncAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, - ValidateQueryResponse::fromXContent, listener, emptySet(), headers); + public void validateQueryAsync(ValidateQueryRequest validateQueryRequest, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, options, + ValidateQueryResponse::fromXContent, listener, emptySet()); } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 91b73974151cc..b96e7f689d1c2 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -2019,7 +2019,7 @@ public void testValidateQuery() throws IOException, InterruptedException { // end::validate-query-request-rewrite // tag::validate-query-execute - ValidateQueryResponse response = client.indices().validateQuery(request); // <1> + ValidateQueryResponse response = client.indices().validateQuery(request, RequestOptions.DEFAULT); // <1> // end::validate-query-execute // tag::validate-query-response @@ -2061,7 +2061,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::validate-query-execute-async - client.indices().validateQueryAsync(request, listener); // <1> + client.indices().validateQueryAsync(request, RequestOptions.DEFAULT, listener); // <1> // end::validate-query-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); From 2d8f6b3c2e5bffc2628888ba19a1b81891bf9ec2 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Wed, 13 Jun 2018 01:49:00 +0200 Subject: [PATCH 5/7] Fixes for review -- added javadoc -- added documentation for setting query to request -- changed to Object.equals for QueryExplanation::equals -- extended ToXContentObject instead of ToXContentFragment for request --- .../elasticsearch/client/IndicesClient.java | 7 +++++ .../IndicesClientDocumentationIT.java | 1 + .../indices/validate_query.asciidoc | 1 + .../validate/query/QueryExplanation.java | 26 ++++--------------- .../validate/query/ValidateQueryRequest.java | 8 +++--- .../query/ValidateQueryResponseTests.java | 6 ++--- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 5bb2f2ea04ca8..9a56c9988c369 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -1067,6 +1067,10 @@ public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest, Re *

* See Validate Query API * on elastic.co + * @param validateQueryRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response */ public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryRequest, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(validateQueryRequest, RequestConverters::validateQuery, options, @@ -1078,6 +1082,9 @@ public ValidateQueryResponse validateQuery(ValidateQueryRequest validateQueryReq *

* See Validate Query API * on elastic.co + * @param validateQueryRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion */ public void validateQueryAsync(ValidateQueryRequest validateQueryRequest, RequestOptions options, ActionListener listener) { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index b96e7f689d1c2..38c09e492b50c 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -2004,6 +2004,7 @@ public void testValidateQuery() throws IOException, InterruptedException { .boolQuery() // <1> .must(QueryBuilders.queryStringQuery("*:*")) .filter(QueryBuilders.termQuery("user", "kimchy")); + request.query(builder); // <2> // end::validate-query-request-query // tag::validate-query-request-explain diff --git a/docs/java-rest/high-level/indices/validate_query.asciidoc b/docs/java-rest/high-level/indices/validate_query.asciidoc index 2946bb05e9f36..3b3b184b02875 100644 --- a/docs/java-rest/high-level/indices/validate_query.asciidoc +++ b/docs/java-rest/high-level/indices/validate_query.asciidoc @@ -21,6 +21,7 @@ The following code snippet builds a sample boolean query. include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[validate-query-request-query] -------------------------------------------------- <1> Build the desired query. +<2> Set it to the request. ==== Optional arguments The following arguments can optionally be provided: diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java index 620f4d6319f69..e330a0b8565fc 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/QueryExplanation.java @@ -71,8 +71,6 @@ public class QueryExplanation implements Streamable, ToXContentFragment { PARSER.declareString(optionalConstructorArg(), new ParseField(ERROR_FIELD)); } - - private String index; private int shard = RANDOM_SHARD; @@ -181,25 +179,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; QueryExplanation other = (QueryExplanation) o; - boolean result; - if (getIndex() == null) { - result = other.getIndex() == null; - } else { - result = getIndex().equals(other.getIndex()); - } - result &= this.getShard() == other.getShard(); - result &= isValid() == other.isValid(); - if (getError() == null) { - result &= other.getError() == null; - } else { - result &= getError().equals(other.getError()); - } - if (getExplanation() == null) { - result &= other.getExplanation() == null; - } else { - result &= getExplanation().equals(other.getExplanation()); - } - return result; + return Objects.equals(getIndex(), other.getIndex()) && + Objects.equals(getShard(), other.getShard()) && + Objects.equals(isValid(), other.isValid()) && + Objects.equals(getError(), other.getError()) && + Objects.equals(getExplanation(), other.getExplanation()); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java index f4baffb4af904..6bbb102df3324 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java @@ -27,7 +27,7 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; @@ -40,7 +40,7 @@ *

* The request requires the query to be set using {@link #query(QueryBuilder)} */ -public class ValidateQueryRequest extends BroadcastRequest implements ToXContentFragment { +public class ValidateQueryRequest extends BroadcastRequest implements ToXContentObject { private QueryBuilder query = new MatchAllQueryBuilder(); @@ -184,8 +184,10 @@ public String toString() { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.field("query"); + builder.startObject() + .field("query"); query.toXContent(builder, params); + builder.endObject(); return builder; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java index b523e25bb379b..d72aae8fa2bd1 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryResponseTests.java @@ -24,7 +24,6 @@ import org.elasticsearch.action.support.broadcast.AbstractBroadcastResponseTestCase; import org.elasticsearch.common.Strings; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.test.AbstractStreamableXContentTestCase; import java.io.IOException; import java.util.ArrayList; @@ -35,7 +34,7 @@ public class ValidateQueryResponseTests extends AbstractBroadcastResponseTestCase { - protected static ValidateQueryResponse createRandomValidateQueryResponse( + private static ValidateQueryResponse createRandomValidateQueryResponse( int totalShards, int successfulShards, int failedShards, List failures) { boolean valid = failedShards == 0; List queryExplanations = new ArrayList<>(totalShards); @@ -51,7 +50,7 @@ protected static ValidateQueryResponse createRandomValidateQueryResponse( ); } - protected static ValidateQueryResponse createRandomValidateQueryResponse() { + private static ValidateQueryResponse createRandomValidateQueryResponse() { int totalShards = randomIntBetween(1, 10); int successfulShards = randomIntBetween(0, totalShards); int failedShards = totalShards - successfulShards; @@ -74,7 +73,6 @@ protected static ValidateQueryResponse createRandomValidateQueryResponse() { queryExplanations.add(queryExplanation); } Collections.shuffle(queryExplanations, random()); - Collections.shuffle(shardFailures, random()); return new ValidateQueryResponse(valid, queryExplanations, totalShards, successfulShards, failedShards, shardFailures); } From 8c9cb3cc3b0e7ccd8be5cb51d64e5b57a3305506 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Wed, 13 Jun 2018 13:34:16 +0200 Subject: [PATCH 6/7] Fixed client documentation --- .../IndicesClientDocumentationIT.java | 83 +++++++++++++++++++ .../high-level/supported-apis.asciidoc | 3 - 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index a917fa3a9a127..99361f7c9a3b3 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -62,6 +62,9 @@ import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; +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.ActiveShardCount; import org.elasticsearch.action.support.DefaultShardOperationFailedException; import org.elasticsearch.action.support.IndicesOptions; @@ -81,6 +84,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; @@ -2128,4 +2132,83 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } + + public void testValidateQuery() throws IOException, InterruptedException { + RestHighLevelClient client = highLevelClient(); + + String index = "some_index"; + createIndex(index, Settings.EMPTY); + + // tag::validate-query-request + ValidateQueryRequest request = new ValidateQueryRequest(index); // <1> + // end::validate-query-request + + // tag::validate-query-request-query + QueryBuilder builder = QueryBuilders + .boolQuery() // <1> + .must(QueryBuilders.queryStringQuery("*:*")) + .filter(QueryBuilders.termQuery("user", "kimchy")); + request.query(builder); // <2> + // end::validate-query-request-query + + // tag::validate-query-request-explain + request.explain(true); // <1> + // end::validate-query-request-explain + + // tag::validate-query-request-allShards + request.allShards(true); // <1> + // end::validate-query-request-allShards + + // tag::validate-query-request-rewrite + request.rewrite(true); // <1> + // end::validate-query-request-rewrite + + // tag::validate-query-execute + ValidateQueryResponse response = client.indices().validateQuery(request, RequestOptions.DEFAULT); // <1> + // end::validate-query-execute + + // tag::validate-query-response + boolean isValid = response.isValid(); // <1> + int totalShards = response.getTotalShards(); // <2> + int successfulShards = response.getSuccessfulShards(); // <3> + int failedShards = response.getFailedShards(); // <4> + if (failedShards > 0) { + for(DefaultShardOperationFailedException failure: response.getShardFailures()) { // <5> + String failedIndex = failure.index(); // <6> + int shardId = failure.shardId(); // <7> + String reason = failure.reason(); // <8> + } + } + for(QueryExplanation explanation: response.getQueryExplanation()) { // <9> + String explanationIndex = explanation.getIndex(); // <10> + int shardId = explanation.getShard(); // <11> + String explanationString = explanation.getExplanation(); // <12> + } + // end::validate-query-response + + // tag::validate-query-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(ValidateQueryResponse validateQueryResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::validate-query-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::validate-query-execute-async + client.indices().validateQueryAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::validate-query-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } } diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index ddaadc6fee7e3..4cd87a521d104 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -104,11 +104,8 @@ include::indices/get_alias.asciidoc[] include::indices/put_settings.asciidoc[] include::indices/get_settings.asciidoc[] include::indices/put_template.asciidoc[] -<<<<<<< HEAD include::indices/validate_query.asciidoc[] -======= include::indices/get_templates.asciidoc[] ->>>>>>> 0bfd18cc8b6ab7e58d1d34c50ae7a3b441799761 == Cluster APIs From e4da255f9755bffc38926bde619cf449312231c6 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Wed, 13 Jun 2018 16:23:10 +0200 Subject: [PATCH 7/7] Fixed formatting --- .../client/RequestConverters.java | 19 +- .../client/RequestConvertersTests.java | 4 +- .../IndicesClientDocumentationIT.java | 236 +++++++++--------- .../validate/query/ValidateQueryRequest.java | 7 +- 4 files changed, 132 insertions(+), 134 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index f7f27628fa0eb..ab85af9f1fd7e 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -491,7 +491,7 @@ static Request update(UpdateRequest updateRequest) throws IOException { XContentType upsertContentType = updateRequest.upsertRequest().getContentType(); if ((xContentType != null) && (xContentType != upsertContentType)) { throw new IllegalStateException("Update request cannot have different content types for doc [" + xContentType + "]" + - " and upsert [" + upsertContentType + "] documents"); + " and upsert [" + upsertContentType + "] documents"); } else { xContentType = upsertContentType; } @@ -580,7 +580,7 @@ static Request searchTemplate(SearchTemplateRequest searchTemplateRequest) throw static Request existsAlias(GetAliasesRequest getAliasesRequest) { if ((getAliasesRequest.indices() == null || getAliasesRequest.indices().length == 0) && - (getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) { + (getAliasesRequest.aliases() == null || getAliasesRequest.aliases().length == 0)) { throw new IllegalArgumentException("existsAlias requires at least an alias or an index"); } String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices(); @@ -629,8 +629,8 @@ static Request shrink(ResizeRequest resizeRequest) throws IOException { private static Request resize(ResizeRequest resizeRequest) throws IOException { String endpoint = new EndpointBuilder().addPathPart(resizeRequest.getSourceIndex()) - .addPathPartAsIs("_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT)) - .addPathPart(resizeRequest.getTargetIndexRequest().index()).build(); + .addPathPartAsIs("_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT)) + .addPathPart(resizeRequest.getTargetIndexRequest().index()).build(); Request request = new Request(HttpPut.METHOD_NAME, endpoint); Params params = new Params(request); @@ -734,7 +734,7 @@ static Request clusterHealth(ClusterHealthRequest healthRequest) { static Request rollover(RolloverRequest rolloverRequest) throws IOException { String endpoint = new EndpointBuilder().addPathPart(rolloverRequest.getAlias()).addPathPartAsIs("_rollover") - .addPathPart(rolloverRequest.getNewIndexName()).build(); + .addPathPart(rolloverRequest.getNewIndexName()).build(); Request request = new Request(HttpPost.METHOD_NAME, endpoint); Params params = new Params(request); @@ -871,7 +871,6 @@ static Request validateQuery(ValidateQueryRequest validateQueryRequest) throws I return request; } - static Request getAlias(GetAliasesRequest getAliasesRequest) { String[] indices = getAliasesRequest.indices() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.indices(); String[] aliases = getAliasesRequest.aliases() == null ? Strings.EMPTY_ARRAY : getAliasesRequest.aliases(); @@ -916,12 +915,12 @@ static String endpoint(String[] indices, String endpoint) { static String endpoint(String[] indices, String[] types, String endpoint) { return new EndpointBuilder().addCommaSeparatedPathParts(indices).addCommaSeparatedPathParts(types) - .addPathPartAsIs(endpoint).build(); + .addPathPartAsIs(endpoint).build(); } static String endpoint(String[] indices, String endpoint, String[] suffixes) { return new EndpointBuilder().addCommaSeparatedPathParts(indices).addPathPartAsIs(endpoint) - .addCommaSeparatedPathParts(suffixes).build(); + .addCommaSeparatedPathParts(suffixes).build(); } static String endpoint(String[] indices, String endpoint, String type) { @@ -1217,14 +1216,14 @@ static XContentType enforceSameContentType(IndexRequest indexRequest, @Nullable XContentType requestContentType = indexRequest.getContentType(); if (requestContentType != XContentType.JSON && requestContentType != XContentType.SMILE) { throw new IllegalArgumentException("Unsupported content-type found for request with content-type [" + requestContentType - + "], only JSON and SMILE are supported"); + + "], only JSON and SMILE are supported"); } if (xContentType == null) { return requestContentType; } if (requestContentType != xContentType) { throw new IllegalArgumentException("Mismatching content-type found for request with content-type [" + requestContentType - + "], previous requests have content-type [" + xContentType + "]"); + + "], previous requests have content-type [" + xContentType + "]"); } return xContentType; } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index 2eb973d9a4339..9f352d757f621 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -713,8 +713,8 @@ public void testSyncedFlush() { Request request = RequestConverters.flushSynced(syncedFlushRequest); StringJoiner endpoint = new StringJoiner("/", "/", ""); if (indices != null && indices.length > 0) { - endpoint.add(String.join(",", indices)); - } + endpoint.add(String.join(",", indices)); + } endpoint.add("_flush/synced"); assertThat(request.getEndpoint(), equalTo(endpoint.toString())); assertThat(request.getParameters(), equalTo(expectedParams)); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 99361f7c9a3b3..9cc28152d03e3 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -248,17 +248,17 @@ public void testDeleteIndexAsync() throws Exception { // tag::delete-index-execute-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(DeleteIndexResponse deleteIndexResponse) { - // <1> - } + new ActionListener() { + @Override + public void onResponse(DeleteIndexResponse deleteIndexResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::delete-index-execute-listener // Replace the empty listener by a blocking listener in test @@ -291,7 +291,7 @@ public void testCreateIndex() throws IOException { { // tag::create-index-request-mappings request.mapping("tweet", // <1> - "{\n" + + "{\n" + " \"tweet\": {\n" + " \"properties\": {\n" + " \"message\": {\n" + @@ -300,7 +300,7 @@ public void testCreateIndex() throws IOException { " }\n" + " }\n" + "}", // <2> - XContentType.JSON); + XContentType.JSON); // end::create-index-request-mappings CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); @@ -382,21 +382,21 @@ public void testCreateIndex() throws IOException { request = new CreateIndexRequest("twitter6"); // tag::create-index-whole-source request.source("{\n" + - " \"settings\" : {\n" + - " \"number_of_shards\" : 1,\n" + - " \"number_of_replicas\" : 0\n" + - " },\n" + - " \"mappings\" : {\n" + - " \"tweet\" : {\n" + - " \"properties\" : {\n" + - " \"message\" : { \"type\" : \"text\" }\n" + - " }\n" + - " }\n" + - " },\n" + - " \"aliases\" : {\n" + - " \"twitter_alias\" : {}\n" + - " }\n" + - "}", XContentType.JSON); // <1> + " \"settings\" : {\n" + + " \"number_of_shards\" : 1,\n" + + " \"number_of_replicas\" : 0\n" + + " },\n" + + " \"mappings\" : {\n" + + " \"tweet\" : {\n" + + " \"properties\" : {\n" + + " \"message\" : { \"type\" : \"text\" }\n" + + " }\n" + + " }\n" + + " },\n" + + " \"aliases\" : {\n" + + " \"twitter_alias\" : {}\n" + + " }\n" + + "}", XContentType.JSON); // <1> // end::create-index-whole-source // tag::create-index-execute @@ -420,18 +420,18 @@ public void testCreateIndexAsync() throws Exception { // tag::create-index-execute-listener ActionListener listener = - new ActionListener() { + new ActionListener() { - @Override - public void onResponse(CreateIndexResponse createIndexResponse) { - // <1> - } + @Override + public void onResponse(CreateIndexResponse createIndexResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::create-index-execute-listener // Replace the empty listener by a blocking listener in test @@ -464,12 +464,12 @@ public void testPutMapping() throws IOException { // tag::put-mapping-request-source request.source( "{\n" + - " \"properties\": {\n" + - " \"message\": {\n" + - " \"type\": \"text\"\n" + - " }\n" + - " }\n" + - "}", // <1> + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + + " }\n" + + " }\n" + + "}", // <1> XContentType.JSON); // end::put-mapping-request-source PutMappingResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT); @@ -746,17 +746,17 @@ public void testOpenIndex() throws Exception { // tag::open-index-execute-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(OpenIndexResponse openIndexResponse) { - // <1> - } + new ActionListener() { + @Override + public void onResponse(OpenIndexResponse openIndexResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::open-index-execute-listener // Replace the empty listener by a blocking listener in test @@ -1017,7 +1017,7 @@ public void testGetSettings() throws Exception { { Settings settings = Settings.builder().put("number_of_shards", 3).build(); CreateIndexResponse createIndexResponse = client.indices().create( - new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); + new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1081,7 +1081,7 @@ public void testGetSettingsWithDefaults() throws Exception { { Settings settings = Settings.builder().put("number_of_shards", 3).build(); CreateIndexResponse createIndexResponse = client.indices().create( - new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); + new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1320,17 +1320,17 @@ public void testCloseIndex() throws Exception { // tag::close-index-execute-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(CloseIndexResponse closeIndexResponse) { - // <1> - } + new ActionListener() { + @Override + public void onResponse(CloseIndexResponse closeIndexResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::close-index-execute-listener // Replace the empty listener by a blocking listener in test @@ -1350,7 +1350,7 @@ public void testExistsAlias() throws Exception { { CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index") - .alias(new Alias("alias")), RequestOptions.DEFAULT); + .alias(new Alias("alias")), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1359,7 +1359,7 @@ public void testExistsAlias() throws Exception { GetAliasesRequest request = new GetAliasesRequest(); GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1"); GetAliasesRequest requestWithAliases = - new GetAliasesRequest(new String[]{"alias1", "alias2"}); + new GetAliasesRequest(new String[]{"alias1", "alias2"}); // end::exists-alias-request // tag::exists-alias-request-alias @@ -1426,7 +1426,7 @@ public void testUpdateAliases() throws Exception { // tag::update-aliases-request IndicesAliasesRequest request = new IndicesAliasesRequest(); // <1> AliasActions aliasAction = - new AliasActions(AliasActions.Type.ADD) + new AliasActions(AliasActions.Type.ADD) .index("index1") .alias("alias1"); // <2> request.addAliasAction(aliasAction); // <3> @@ -1434,21 +1434,21 @@ public void testUpdateAliases() throws Exception { // tag::update-aliases-request2 AliasActions addIndexAction = - new AliasActions(AliasActions.Type.ADD) + new AliasActions(AliasActions.Type.ADD) .index("index1") .alias("alias1") .filter("{\"term\":{\"year\":2016}}"); // <1> AliasActions addIndicesAction = - new AliasActions(AliasActions.Type.ADD) + new AliasActions(AliasActions.Type.ADD) .indices("index1", "index2") .alias("alias2") .routing("1"); // <2> AliasActions removeAction = - new AliasActions(AliasActions.Type.REMOVE) + new AliasActions(AliasActions.Type.REMOVE) .index("index3") .alias("alias3"); // <3> AliasActions removeIndexAction = - new AliasActions(AliasActions.Type.REMOVE_INDEX) + new AliasActions(AliasActions.Type.REMOVE_INDEX) .index("index4"); // <4> // end::update-aliases-request2 @@ -1463,7 +1463,7 @@ public void testUpdateAliases() throws Exception { // tag::update-aliases-execute IndicesAliasesResponse indicesAliasesResponse = - client.indices().updateAliases(request, RequestOptions.DEFAULT); + client.indices().updateAliases(request, RequestOptions.DEFAULT); // end::update-aliases-execute // tag::update-aliases-response @@ -1479,17 +1479,17 @@ public void testUpdateAliases() throws Exception { // tag::update-aliases-execute-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(IndicesAliasesResponse indicesAliasesResponse) { - // <1> - } + new ActionListener() { + @Override + public void onResponse(IndicesAliasesResponse indicesAliasesResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::update-aliases-execute-listener // Replace the empty listener by a blocking listener in test @@ -1513,7 +1513,7 @@ public void testShrinkIndex() throws Exception { String firstNode = ((Map) nodes.get("nodes")).keySet().iterator().next(); createIndex("source_index", Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build()); updateIndexSettings("source_index", Settings.builder().put("index.routing.allocation.require._name", firstNode) - .put("index.blocks.write", true)); + .put("index.blocks.write", true)); } // tag::shrink-index-request @@ -1534,8 +1534,8 @@ public void testShrinkIndex() throws Exception { // end::shrink-index-request-waitForActiveShards // tag::shrink-index-request-settings request.getTargetIndexRequest().settings(Settings.builder() - .put("index.number_of_shards", 2) // <1> - .putNull("index.routing.allocation.require._name")); // <2> + .put("index.number_of_shards", 2) // <1> + .putNull("index.routing.allocation.require._name")); // <2> // end::shrink-index-request-settings // tag::shrink-index-request-aliases request.getTargetIndexRequest().alias(new Alias("target_alias")); // <1> @@ -1582,7 +1582,7 @@ public void testSplitIndex() throws Exception { { createIndex("source_index", Settings.builder().put("index.number_of_shards", 2).put("index.number_of_replicas", 0) - .put("index.number_of_routing_shards", 4).build()); + .put("index.number_of_routing_shards", 4).build()); updateIndexSettings("source_index", Settings.builder().put("index.blocks.write", true)); } @@ -1605,7 +1605,7 @@ public void testSplitIndex() throws Exception { // end::split-index-request-waitForActiveShards // tag::split-index-request-settings request.getTargetIndexRequest().settings(Settings.builder() - .put("index.number_of_shards", 4)); // <1> + .put("index.number_of_shards", 4)); // <1> // end::split-index-request-settings // tag::split-index-request-aliases request.getTargetIndexRequest().alias(new Alias("target_alias")); // <1> @@ -1678,7 +1678,7 @@ public void testRolloverIndex() throws Exception { // end::rollover-request-waitForActiveShards // tag::rollover-request-settings request.getCreateIndexRequest().settings(Settings.builder() - .put("index.number_of_shards", 4)); // <1> + .put("index.number_of_shards", 4)); // <1> // end::rollover-request-settings // tag::rollover-request-mapping request.getCreateIndexRequest().mapping("type", "field", "type=keyword"); // <1> @@ -1738,7 +1738,7 @@ public void testGetAlias() throws Exception { { CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index").alias(new Alias("alias")), - RequestOptions.DEFAULT); + RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1747,7 +1747,7 @@ public void testGetAlias() throws Exception { GetAliasesRequest request = new GetAliasesRequest(); GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1"); GetAliasesRequest requestWithAliases = - new GetAliasesRequest(new String[]{"alias1", "alias2"}); + new GetAliasesRequest(new String[]{"alias1", "alias2"}); // end::get-alias-request // tag::get-alias-request-alias @@ -1778,17 +1778,17 @@ public void testGetAlias() throws Exception { // tag::get-alias-listener ActionListener listener = - new ActionListener() { - @Override - public void onResponse(GetAliasesResponse getAliasesResponse) { - // <1> - } + new ActionListener() { + @Override + public void onResponse(GetAliasesResponse getAliasesResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::get-alias-listener // Replace the empty listener by a blocking listener in test @@ -1814,7 +1814,7 @@ public void testIndexPutSettings() throws Exception { // tag::put-settings-request UpdateSettingsRequest request = new UpdateSettingsRequest("index1"); // <1> UpdateSettingsRequest requestMultiple = - new UpdateSettingsRequest("index1", "index2"); // <2> + new UpdateSettingsRequest("index1", "index2"); // <2> UpdateSettingsRequest requestAll = new UpdateSettingsRequest(); // <3> // end::put-settings-request @@ -1822,7 +1822,7 @@ public void testIndexPutSettings() throws Exception { String settingKey = "index.number_of_replicas"; int settingValue = 0; Settings settings = - Settings.builder() + Settings.builder() .put(settingKey, settingValue) .build(); // <1> // end::put-settings-create-settings @@ -1833,7 +1833,7 @@ public void testIndexPutSettings() throws Exception { { // tag::put-settings-settings-builder Settings.Builder settingsBuilder = - Settings.builder() + Settings.builder() .put(settingKey, settingValue); request.settings(settingsBuilder); // <1> // end::put-settings-settings-builder @@ -1848,8 +1848,8 @@ public void testIndexPutSettings() throws Exception { { // tag::put-settings-settings-source request.settings( - "{\"index.number_of_replicas\": \"2\"}" - , XContentType.JSON); // <1> + "{\"index.number_of_replicas\": \"2\"}" + , XContentType.JSON); // <1> // end::put-settings-settings-source } @@ -1870,7 +1870,7 @@ public void testIndexPutSettings() throws Exception { // tag::put-settings-execute UpdateSettingsResponse updateSettingsResponse = - client.indices().putSettings(request, RequestOptions.DEFAULT); + client.indices().putSettings(request, RequestOptions.DEFAULT); // end::put-settings-execute // tag::put-settings-response @@ -1880,18 +1880,18 @@ public void testIndexPutSettings() throws Exception { // tag::put-settings-execute-listener ActionListener listener = - new ActionListener() { + new ActionListener() { - @Override - public void onResponse(UpdateSettingsResponse updateSettingsResponse) { - // <1> - } + @Override + public void onResponse(UpdateSettingsResponse updateSettingsResponse) { + // <1> + } - @Override - public void onFailure(Exception e) { - // <2> - } - }; + @Override + public void onFailure(Exception e) { + // <2> + } + }; // end::put-settings-execute-listener // Replace the empty listener by a blocking listener in test @@ -2073,7 +2073,7 @@ public void testGetTemplates() throws Exception { putRequest.patterns(Arrays.asList("pattern-1", "log-*")); putRequest.settings(Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 1)); putRequest.mapping("tweet", - "{\n" + + "{\n" + " \"tweet\": {\n" + " \"properties\": {\n" + " \"message\": {\n" + diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java index 6bbb102df3324..7694e7583c898 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/validate/query/ValidateQueryRequest.java @@ -184,10 +184,9 @@ public String toString() { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject() - .field("query"); + builder.startObject(); + builder.field("query"); query.toXContent(builder, params); - builder.endObject(); - return builder; + return builder.endObject(); } }