This commit is contained in:
Shay Banon 2011-12-29 14:17:50 +02:00
commit e47ec96ca2
16 changed files with 1070 additions and 2 deletions

View File

@ -67,6 +67,7 @@ public class TransportActions {
public static final String ANALYZE = "indices/analyze";
public static final String PUT_INDEX_TEMPLATE = "indices/putIndexTemplate";
public static final String DELETE_INDEX_TEMPLATE = "indices/deleteIndexTemplate";
public static final String VALIDATE_QUERY = "indices/validateQuery";
public static class Gateway {
public static final String SNAPSHOT = "indices/gateway/snapshot";

View File

@ -0,0 +1,120 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.action.support.broadcast.BroadcastShardOperationRequest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
/**
* Internal validate request executed directly against a specific index shard.
*
*
*/
class ShardValidateQueryRequest extends BroadcastShardOperationRequest {
private byte[] querySource;
private int querySourceOffset;
private int querySourceLength;
private String[] types = Strings.EMPTY_ARRAY;
@Nullable
private String[] filteringAliases;
ShardValidateQueryRequest() {
}
public ShardValidateQueryRequest(String index, int shardId, @Nullable String[] filteringAliases, ValidateQueryRequest request) {
super(index, shardId);
this.querySource = request.querySource();
this.querySourceOffset = request.querySourceOffset();
this.querySourceLength = request.querySourceLength();
this.types = request.types();
this.filteringAliases = filteringAliases;
}
public byte[] querySource() {
return querySource;
}
public int querySourceOffset() {
return querySourceOffset;
}
public int querySourceLength() {
return querySourceLength;
}
public String[] types() {
return this.types;
}
public String[] filteringAliases() {
return filteringAliases;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
querySourceLength = in.readVInt();
querySourceOffset = 0;
querySource = new byte[querySourceLength];
in.readFully(querySource);
int typesSize = in.readVInt();
if (typesSize > 0) {
types = new String[typesSize];
for (int i = 0; i < typesSize; i++) {
types[i] = in.readUTF();
}
}
int aliasesSize = in.readVInt();
if (aliasesSize > 0) {
filteringAliases = new String[aliasesSize];
for (int i = 0; i < aliasesSize; i++) {
filteringAliases[i] = in.readUTF();
}
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(querySourceLength);
out.writeBytes(querySource, querySourceOffset, querySourceLength);
out.writeVInt(types.length);
for (String type : types) {
out.writeUTF(type);
}
if (filteringAliases != null) {
out.writeVInt(filteringAliases.length);
for (String alias : filteringAliases) {
out.writeUTF(alias);
}
} else {
out.writeVInt(0);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.action.support.broadcast.BroadcastShardOperationResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
/**
* Internal validate response of a shard validate request executed directly against a specific shard.
*
*
*/
class ShardValidateQueryResponse extends BroadcastShardOperationResponse {
private boolean valid;
ShardValidateQueryResponse() {
}
public ShardValidateQueryResponse(String index, int shardId, boolean valid) {
super(index, shardId);
this.valid = valid;
}
boolean valid() {
return this.valid;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
valid = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeBoolean(valid);
}
}

View File

@ -0,0 +1,154 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.ShardOperationFailedException;
import org.elasticsearch.action.TransportActions;
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.BroadcastShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.TransportBroadcastOperationAction;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.block.ClusterBlockLevel;
import org.elasticsearch.cluster.routing.GroupShardsIterator;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.IndexQueryParserService;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.shard.service.IndexShard;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceArray;
import static com.google.common.collect.Lists.newArrayList;
/**
*
*/
public class TransportValidateQueryAction extends TransportBroadcastOperationAction<ValidateQueryRequest, ValidateQueryResponse, ShardValidateQueryRequest, ShardValidateQueryResponse> {
private final IndicesService indicesService;
@Inject
public TransportValidateQueryAction(Settings settings, ThreadPool threadPool, ClusterService clusterService, TransportService transportService, IndicesService indicesService) {
super(settings, threadPool, clusterService, transportService);
this.indicesService = indicesService;
}
@Override
protected String executor() {
return ThreadPool.Names.SEARCH;
}
@Override
protected String transportAction() {
return TransportActions.Admin.Indices.VALIDATE_QUERY;
}
@Override
protected String transportShardAction() {
return "indices/validateQuery/shard";
}
@Override
protected ValidateQueryRequest newRequest() {
return new ValidateQueryRequest();
}
@Override
protected ShardValidateQueryRequest newShardRequest() {
return new ShardValidateQueryRequest();
}
@Override
protected ShardValidateQueryRequest newShardRequest(ShardRouting shard, ValidateQueryRequest request) {
String[] filteringAliases = clusterService.state().metaData().filteringAliases(shard.index(), request.indices());
return new ShardValidateQueryRequest(shard.index(), shard.id(), filteringAliases, request);
}
@Override
protected ShardValidateQueryResponse newShardResponse() {
return new ShardValidateQueryResponse();
}
@Override
protected GroupShardsIterator shards(ValidateQueryRequest request, String[] concreteIndices, ClusterState clusterState) {
// Hard-code routing to limit request to a single shard.
Map<String, Set<String>> routingMap = clusterState.metaData().resolveSearchRouting("0", request.indices());
return clusterService.operationRouting().searchShards(clusterState, request.indices(), concreteIndices, null, routingMap, "_local");
}
@Override
protected void checkBlock(ValidateQueryRequest request, String[] concreteIndices, ClusterState state) {
for (String index : concreteIndices) {
state.blocks().indexBlocked(ClusterBlockLevel.READ, index);
}
}
@Override
protected ValidateQueryResponse newResponse(ValidateQueryRequest request, AtomicReferenceArray shardsResponses, ClusterState clusterState) {
int successfulShards = 0;
int failedShards = 0;
boolean valid = true;
List<ShardOperationFailedException> shardFailures = null;
for (int i = 0; i < shardsResponses.length(); i++) {
Object shardResponse = shardsResponses.get(i);
if (shardResponse == null) {
failedShards++;
} else if (shardResponse instanceof BroadcastShardOperationFailedException) {
failedShards++;
if (shardFailures == null) {
shardFailures = newArrayList();
}
shardFailures.add(new DefaultShardOperationFailedException((BroadcastShardOperationFailedException) shardResponse));
} else {
valid = valid && ((ShardValidateQueryResponse) shardResponse).valid();
successfulShards++;
}
}
return new ValidateQueryResponse(valid, shardsResponses.length(), successfulShards, failedShards, shardFailures);
}
@Override
protected ShardValidateQueryResponse shardOperation(ShardValidateQueryRequest request) throws ElasticSearchException {
IndexQueryParserService queryParserService = indicesService.indexServiceSafe(request.index()).queryParserService();
boolean valid;
if (request.querySourceLength() == 0) {
valid = true;
} else {
try {
queryParserService.parse(request.querySource(), request.querySourceOffset(), request.querySourceLength());
valid = true;
} catch (QueryParsingException e) {
valid = false;
} catch (AssertionError e) {
valid = false;
}
}
return new ShardValidateQueryResponse(request.index(), request.shardId(), valid);
}
}

View File

@ -0,0 +1,253 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.ElasticSearchGenerationException;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.broadcast.BroadcastOperationRequest;
import org.elasticsearch.action.support.broadcast.BroadcastOperationThreading;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.Required;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.Unicode;
import org.elasticsearch.common.io.BytesStream;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
/**
* A request to validate a specific query.
* <p/>
* <p>The request requires the query source to be set either using {@link #query(org.elasticsearch.index.query.QueryBuilder)},
* or {@link #query(byte[])}.
*
*
*/
public class ValidateQueryRequest extends BroadcastOperationRequest {
private static final XContentType contentType = Requests.CONTENT_TYPE;
private byte[] querySource;
private int querySourceOffset;
private int querySourceLength;
private boolean querySourceUnsafe;
private String[] types = Strings.EMPTY_ARRAY;
ValidateQueryRequest() {
}
/**
* Constructs a new validate request against the provided indices. No indices provided means it will
* run against all indices.
*/
public ValidateQueryRequest(String... indices) {
super(indices);
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = super.validate();
return validationException;
}
/**
* Controls the operation threading model.
*/
@Override
public ValidateQueryRequest operationThreading(BroadcastOperationThreading operationThreading) {
super.operationThreading(operationThreading);
return this;
}
@Override
protected void beforeStart() {
if (querySourceUnsafe) {
querySource = Arrays.copyOfRange(querySource, querySourceOffset, querySourceOffset + querySourceLength);
querySourceOffset = 0;
querySourceUnsafe = false;
}
}
/**
* Should the listener be called on a separate thread if needed.
*/
@Override
public ValidateQueryRequest listenerThreaded(boolean threadedListener) {
super.listenerThreaded(threadedListener);
return this;
}
public ValidateQueryRequest indices(String... indices) {
this.indices = indices;
return this;
}
/**
* The query source to execute.
*/
byte[] querySource() {
return querySource;
}
int querySourceOffset() {
return querySourceOffset;
}
int querySourceLength() {
return querySourceLength;
}
/**
* The query source to execute.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
@Required
public ValidateQueryRequest query(QueryBuilder queryBuilder) {
BytesStream bos = queryBuilder.buildAsUnsafeBytes();
this.querySource = bos.underlyingBytes();
this.querySourceOffset = 0;
this.querySourceLength = bos.size();
this.querySourceUnsafe = true;
return this;
}
/**
* The query source to execute in the form of a map.
*/
@Required
public ValidateQueryRequest query(Map querySource) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
builder.map(querySource);
return query(builder);
} catch (IOException e) {
throw new ElasticSearchGenerationException("Failed to generate [" + querySource + "]", e);
}
}
@Required
public ValidateQueryRequest query(XContentBuilder builder) {
try {
this.querySource = builder.underlyingBytes();
this.querySourceOffset = 0;
this.querySourceLength = builder.underlyingBytesLength();
this.querySourceUnsafe = false;
return this;
} catch (IOException e) {
throw new ElasticSearchGenerationException("Failed to generate [" + builder + "]", e);
}
}
/**
* The query source to validate. It is preferable to use either {@link #query(byte[])}
* or {@link #query(org.elasticsearch.index.query.QueryBuilder)}.
*/
@Required
public ValidateQueryRequest query(String querySource) {
UnicodeUtil.UTF8Result result = Unicode.fromStringAsUtf8(querySource);
this.querySource = result.result;
this.querySourceOffset = 0;
this.querySourceLength = result.length;
this.querySourceUnsafe = true;
return this;
}
/**
* The query source to validate.
*/
@Required
public ValidateQueryRequest query(byte[] querySource) {
return query(querySource, 0, querySource.length, false);
}
/**
* The query source to validate.
*/
@Required
public ValidateQueryRequest query(byte[] querySource, int offset, int length, boolean unsafe) {
this.querySource = querySource;
this.querySourceOffset = offset;
this.querySourceLength = length;
this.querySourceUnsafe = unsafe;
return this;
}
/**
* The types of documents the query will run against. Defaults to all types.
*/
String[] types() {
return this.types;
}
/**
* The types of documents the query will run against. Defaults to all types.
*/
public ValidateQueryRequest types(String... types) {
this.types = types;
return this;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
querySourceUnsafe = false;
querySourceOffset = 0;
querySourceLength = in.readVInt();
querySource = new byte[querySourceLength];
in.readFully(querySource);
int typesSize = in.readVInt();
if (typesSize > 0) {
types = new String[typesSize];
for (int i = 0; i < typesSize; i++) {
types[i] = in.readUTF();
}
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(querySourceLength);
out.writeBytes(querySource, querySourceOffset, querySourceLength);
out.writeVInt(types.length);
for (String type : types) {
out.writeUTF(type);
}
}
@Override
public String toString() {
return "[" + Arrays.toString(indices) + "]" + Arrays.toString(types) + ", querySource[" + Unicode.fromBytes(querySource) + "]";
}
}

View File

@ -0,0 +1,73 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.action.ShardOperationFailedException;
import org.elasticsearch.action.support.broadcast.BroadcastOperationResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
import java.util.List;
/**
* The response of the validate action.
*
*
*/
public class ValidateQueryResponse extends BroadcastOperationResponse {
private boolean valid;
ValidateQueryResponse() {
}
ValidateQueryResponse(boolean valid, int totalShards, int successfulShards, int failedShards, List<ShardOperationFailedException> shardFailures) {
super(totalShards, successfulShards, failedShards, shardFailures);
this.valid = valid;
}
/**
* A boolean denoting whether the query is valid.
*/
public boolean valid() {
return valid;
}
/**
* A boolean denoting whether the query is valid.
*/
public boolean getValid() {
return valid;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
valid = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeBoolean(valid);
}
}

View File

@ -0,0 +1,23 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.
*/
/**
* Validate action.
*/
package org.elasticsearch.action.admin.indices.validate.query;

View File

@ -61,6 +61,8 @@ import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplat
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
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.client.action.admin.indices.alias.IndicesAliasesRequestBuilder;
import org.elasticsearch.client.action.admin.indices.analyze.AnalyzeRequestBuilder;
import org.elasticsearch.client.action.admin.indices.cache.clear.ClearIndicesCacheRequestBuilder;
@ -81,6 +83,7 @@ import org.elasticsearch.client.action.admin.indices.stats.IndicesStatsRequestBu
import org.elasticsearch.client.action.admin.indices.status.IndicesStatusRequestBuilder;
import org.elasticsearch.client.action.admin.indices.template.delete.DeleteIndexTemplateRequestBuilder;
import org.elasticsearch.client.action.admin.indices.template.put.PutIndexTemplateRequestBuilder;
import org.elasticsearch.client.action.admin.indices.validate.query.ValidateQueryRequestBuilder;
import org.elasticsearch.common.Nullable;
/**
@ -537,4 +540,27 @@ public interface IndicesAdminClient {
* @param name The name of the template.
*/
DeleteIndexTemplateRequestBuilder prepareDeleteTemplate(String name);
/**
* Validate a query for correctness.
*
* @param request The count request
* @return The result future
* @see Requests#countRequest(String...)
*/
ActionFuture<ValidateQueryResponse> validateQuery(ValidateQueryRequest request);
/**
* Validate a query for correctness.
*
* @param request The count request
* @param listener A listener to be notified of the result
* @see Requests#countRequest(String...)
*/
void validateQuery(ValidateQueryRequest request, ActionListener<ValidateQueryResponse> listener);
/**
* Validate a query for correctness.
*/
ValidateQueryRequestBuilder prepareValidateQuery(String... indices);
}

View File

@ -0,0 +1,75 @@
package org.elasticsearch.client.action.admin.indices.validate.query;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.action.support.broadcast.BroadcastOperationThreading;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.action.admin.indices.support.BaseIndicesRequestBuilder;
import org.elasticsearch.index.query.QueryBuilder;
/**
*
*/
public class ValidateQueryRequestBuilder extends BaseIndicesRequestBuilder<ValidateQueryRequest, ValidateQueryResponse> {
public ValidateQueryRequestBuilder(IndicesAdminClient client) {
super(client, new ValidateQueryRequest());
}
/**
* Sets the indices the query validation will run against.
*/
public ValidateQueryRequestBuilder setIndices(String... indices) {
request.indices(indices);
return this;
}
/**
* The types of documents the query will run against. Defaults to all types.
*/
public ValidateQueryRequestBuilder setTypes(String... types) {
request.types(types);
return this;
}
/**
* The query source to validate.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
public ValidateQueryRequestBuilder setQuery(QueryBuilder queryBuilder) {
request.query(queryBuilder);
return this;
}
/**
* The query source to validate.
*
* @see org.elasticsearch.index.query.QueryBuilders
*/
public ValidateQueryRequestBuilder setQuery(byte[] querySource) {
request.query(querySource);
return this;
}
/**
* Controls the operation threading model.
*/
public ValidateQueryRequestBuilder setOperationThreading(BroadcastOperationThreading operationThreading) {
request.operationThreading(operationThreading);
return this;
}
/**
* Should the listener be called on a separate thread if needed.
*/
public ValidateQueryRequestBuilder setListenerThreaded(boolean threadedListener) {
request.listenerThreaded(threadedListener);
return this;
}
@Override
protected void doExecute(ActionListener<ValidateQueryResponse> listener) {
client.validateQuery(request, listener);
}
}

View File

@ -81,6 +81,9 @@ import org.elasticsearch.action.admin.indices.template.delete.TransportDeleteInd
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.action.admin.indices.template.put.TransportPutIndexTemplateAction;
import org.elasticsearch.action.admin.indices.validate.query.TransportValidateQueryAction;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.support.AbstractIndicesAdminClient;
import org.elasticsearch.common.inject.Inject;
@ -134,6 +137,8 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement
private final TransportDeleteIndexTemplateAction deleteIndexTemplateAction;
private final TransportValidateQueryAction validateQueryAction;
@Inject
public NodeIndicesAdminClient(Settings settings, ThreadPool threadPool, TransportIndicesExistsAction indicesExistsAction, TransportIndicesStatsAction indicesStatsAction, TransportIndicesStatusAction indicesStatusAction, TransportIndicesSegmentsAction indicesSegmentsAction,
TransportCreateIndexAction createIndexAction, TransportDeleteIndexAction deleteIndexAction,
@ -142,7 +147,7 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement
TransportPutMappingAction putMappingAction, TransportDeleteMappingAction deleteMappingAction, TransportGatewaySnapshotAction gatewaySnapshotAction,
TransportIndicesAliasesAction indicesAliasesAction, TransportClearIndicesCacheAction clearIndicesCacheAction,
TransportUpdateSettingsAction updateSettingsAction, TransportAnalyzeAction analyzeAction,
TransportPutIndexTemplateAction putIndexTemplateAction, TransportDeleteIndexTemplateAction deleteIndexTemplateAction) {
TransportPutIndexTemplateAction putIndexTemplateAction, TransportDeleteIndexTemplateAction deleteIndexTemplateAction, TransportValidateQueryAction validateQueryAction) {
this.threadPool = threadPool;
this.indicesExistsAction = indicesExistsAction;
this.indicesStatsAction = indicesStatsAction;
@ -164,6 +169,7 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement
this.analyzeAction = analyzeAction;
this.putIndexTemplateAction = putIndexTemplateAction;
this.deleteIndexTemplateAction = deleteIndexTemplateAction;
this.validateQueryAction = validateQueryAction;
}
@Override
@ -370,4 +376,14 @@ public class NodeIndicesAdminClient extends AbstractIndicesAdminClient implement
public void deleteTemplate(DeleteIndexTemplateRequest request, ActionListener<DeleteIndexTemplateResponse> listener) {
deleteIndexTemplateAction.execute(request, listener);
}
@Override
public ActionFuture<ValidateQueryResponse> validateQuery(ValidateQueryRequest request) {
return validateQueryAction.execute(request);
}
@Override
public void validateQuery(ValidateQueryRequest request, ActionListener<ValidateQueryResponse> listener) {
validateQueryAction.execute(request, listener);
}
}

View File

@ -39,6 +39,7 @@ import org.elasticsearch.client.action.admin.indices.stats.IndicesStatsRequestBu
import org.elasticsearch.client.action.admin.indices.status.IndicesStatusRequestBuilder;
import org.elasticsearch.client.action.admin.indices.template.delete.DeleteIndexTemplateRequestBuilder;
import org.elasticsearch.client.action.admin.indices.template.put.PutIndexTemplateRequestBuilder;
import org.elasticsearch.client.action.admin.indices.validate.query.ValidateQueryRequestBuilder;
import org.elasticsearch.client.internal.InternalIndicesAdminClient;
import org.elasticsearch.common.Nullable;
@ -151,4 +152,9 @@ public abstract class AbstractIndicesAdminClient implements InternalIndicesAdmin
public DeleteIndexTemplateRequestBuilder prepareDeleteTemplate(String name) {
return new DeleteIndexTemplateRequestBuilder(this, name);
}
@Override
public ValidateQueryRequestBuilder prepareValidateQuery(String... indices) {
return new ValidateQueryRequestBuilder(this).setIndices(indices);
}
}

View File

@ -0,0 +1,25 @@
package org.elasticsearch.client.transport.action.admin.indices.validate.query;
import org.elasticsearch.action.TransportActions;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.client.transport.action.support.BaseClientTransportAction;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.transport.TransportService;
/**
*
*/
public class ClientTransportValidateQueryAction extends BaseClientTransportAction<ValidateQueryRequest, ValidateQueryResponse> {
@Inject
public ClientTransportValidateQueryAction(Settings settings, TransportService transportService) {
super(settings, transportService, ValidateQueryResponse.class);
}
@Override
protected String action() {
return TransportActions.Admin.Indices.VALIDATE_QUERY;
}
}

View File

@ -62,6 +62,8 @@ import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplat
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
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.client.IndicesAdminClient;
import org.elasticsearch.client.support.AbstractIndicesAdminClient;
import org.elasticsearch.client.transport.TransportClientNodesService;
@ -85,6 +87,7 @@ import org.elasticsearch.client.transport.action.admin.indices.stats.ClientTrans
import org.elasticsearch.client.transport.action.admin.indices.status.ClientTransportIndicesStatusAction;
import org.elasticsearch.client.transport.action.admin.indices.template.delete.ClientTransportDeleteIndexTemplateAction;
import org.elasticsearch.client.transport.action.admin.indices.template.put.ClientTransportPutIndexTemplateAction;
import org.elasticsearch.client.transport.action.admin.indices.validate.query.ClientTransportValidateQueryAction;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -139,6 +142,8 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli
private final ClientTransportDeleteIndexTemplateAction deleteIndexTemplateAction;
private final ClientTransportValidateQueryAction validateQueryAction;
@Inject
public InternalTransportIndicesAdminClient(Settings settings, TransportClientNodesService nodesService, ThreadPool threadPool,
ClientTransportIndicesExistsAction indicesExistsAction, ClientTransportIndicesStatusAction indicesStatusAction, ClientTransportIndicesStatsAction indicesStatsAction, ClientTransportIndicesSegmentsAction indicesSegmentsAction,
@ -147,7 +152,7 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli
ClientTransportRefreshAction refreshAction, ClientTransportFlushAction flushAction, ClientTransportOptimizeAction optimizeAction,
ClientTransportPutMappingAction putMappingAction, ClientTransportDeleteMappingAction deleteMappingAction, ClientTransportGatewaySnapshotAction gatewaySnapshotAction,
ClientTransportIndicesAliasesAction indicesAliasesAction, ClientTransportClearIndicesCacheAction clearIndicesCacheAction,
ClientTransportUpdateSettingsAction updateSettingsAction, ClientTransportAnalyzeAction analyzeAction,
ClientTransportUpdateSettingsAction updateSettingsAction, ClientTransportAnalyzeAction analyzeAction, ClientTransportValidateQueryAction validateQueryAction,
ClientTransportPutIndexTemplateAction putIndexTemplateAction, ClientTransportDeleteIndexTemplateAction deleteIndexTemplateAction) {
this.nodesService = nodesService;
this.threadPool = threadPool;
@ -171,6 +176,7 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli
this.analyzeAction = analyzeAction;
this.putIndexTemplateAction = putIndexTemplateAction;
this.deleteIndexTemplateAction = deleteIndexTemplateAction;
this.validateQueryAction = validateQueryAction;
}
@Override
@ -577,4 +583,24 @@ public class InternalTransportIndicesAdminClient extends AbstractIndicesAdminCli
}
}, listener);
}
@Override
public ActionFuture<ValidateQueryResponse> validateQuery(final ValidateQueryRequest request) {
return nodesService.execute(new TransportClientNodesService.NodeCallback<ActionFuture<ValidateQueryResponse>>() {
@Override
public ActionFuture<ValidateQueryResponse> doWithNode(DiscoveryNode node) throws ElasticSearchException {
return validateQueryAction.execute(node, request);
}
});
}
@Override
public void validateQuery(final ValidateQueryRequest request, final ActionListener<ValidateQueryResponse> listener) {
nodesService.execute(new TransportClientNodesService.NodeListenerCallback<ValidateQueryResponse>() {
@Override
public void doWithNode(DiscoveryNode node, ActionListener<ValidateQueryResponse> listener) throws ElasticSearchException {
validateQueryAction.execute(node, request, listener);
}
}, listener);
}
}

View File

@ -58,6 +58,7 @@ import org.elasticsearch.rest.action.admin.indices.status.RestIndicesStatusActio
import org.elasticsearch.rest.action.admin.indices.template.delete.RestDeleteIndexTemplateAction;
import org.elasticsearch.rest.action.admin.indices.template.get.RestGetIndexTemplateAction;
import org.elasticsearch.rest.action.admin.indices.template.put.RestPutIndexTemplateAction;
import org.elasticsearch.rest.action.admin.indices.validate.query.RestValidateQueryAction;
import org.elasticsearch.rest.action.bulk.RestBulkAction;
import org.elasticsearch.rest.action.count.RestCountAction;
import org.elasticsearch.rest.action.delete.RestDeleteAction;
@ -149,6 +150,8 @@ public class RestActionModule extends AbstractModule {
bind(RestSearchAction.class).asEagerSingleton();
bind(RestSearchScrollAction.class).asEagerSingleton();
bind(RestValidateQueryAction.class).asEagerSingleton();
bind(RestMoreLikeThisAction.class).asEagerSingleton();

View File

@ -0,0 +1,122 @@
/*
* Licensed to ElasticSearch and Shay Banon 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.rest.action.admin.indices.validate.query;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.broadcast.BroadcastOperationThreading;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestActions;
import org.elasticsearch.rest.action.support.RestXContentBuilder;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestStatus.BAD_REQUEST;
import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.action.support.RestActions.buildBroadcastShardsHeader;
import static org.elasticsearch.rest.action.support.RestActions.splitTypes;
/**
*
*/
public class RestValidateQueryAction extends BaseRestHandler {
@Inject
public RestValidateQueryAction(Settings settings, Client client, RestController controller) {
super(settings, client);
controller.registerHandler(GET, "/_validate/query", this);
controller.registerHandler(POST, "/_validate/query", this);
controller.registerHandler(GET, "/{index}/_validate/query", this);
controller.registerHandler(POST, "/{index}/_validate/query", this);
controller.registerHandler(GET, "/{index}/{type}/_validate/query", this);
controller.registerHandler(POST, "/{index}/{type}/_validate/query", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel) {
ValidateQueryRequest validateQueryRequest = new ValidateQueryRequest(RestActions.splitIndices(request.param("index")));
// we just send back a response, no need to fork a listener
validateQueryRequest.listenerThreaded(false);
try {
BroadcastOperationThreading operationThreading = BroadcastOperationThreading.fromString(request.param("operation_threading"), BroadcastOperationThreading.SINGLE_THREAD);
if (operationThreading == BroadcastOperationThreading.NO_THREADS) {
// since we don't spawn, don't allow no_threads, but change it to a single thread
operationThreading = BroadcastOperationThreading.SINGLE_THREAD;
}
validateQueryRequest.operationThreading(operationThreading);
if (request.hasContent()) {
validateQueryRequest.query(request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength(), true);
} else {
String source = request.param("source");
if (source != null) {
validateQueryRequest.query(source);
} else {
byte[] querySource = RestActions.parseQuerySource(request);
if (querySource != null) {
validateQueryRequest.query(querySource);
}
}
}
validateQueryRequest.types(splitTypes(request.param("type")));
} catch (Exception e) {
try {
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
channel.sendResponse(new XContentRestResponse(request, BAD_REQUEST, builder.startObject().field("error", e.getMessage()).endObject()));
} catch (IOException e1) {
logger.error("Failed to send failure response", e1);
}
return;
}
client.admin().indices().validateQuery(validateQueryRequest, new ActionListener<ValidateQueryResponse>() {
@Override
public void onResponse(ValidateQueryResponse response) {
try {
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
builder.startObject();
builder.field("valid", response.valid());
buildBroadcastShardsHeader(builder, response);
builder.endObject();
channel.sendResponse(new XContentRestResponse(request, OK, builder));
} catch (Exception e) {
onFailure(e);
}
}
@Override
public void onFailure(Throwable e) {
try {
channel.sendResponse(new XContentThrowableRestResponse(request, e));
} catch (IOException e1) {
logger.error("Failed to send failure response", e1);
}
}
});
}
}

View File

@ -0,0 +1,84 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.test.integration.validate;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.test.integration.AbstractNodesTests;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
*
*/
public class SimpleValidateQueryTests extends AbstractNodesTests {
private Client client;
@BeforeClass
public void createNodes() throws Exception {
startNode("node1");
startNode("node2");
client = getClient();
}
@AfterClass
public void closeNodes() {
client.close();
closeAllNodes();
}
protected Client getClient() {
return client("node1");
}
@Test
public void simpleValidateQuery() throws Exception {
client.admin().indices().prepareDelete().execute().actionGet();
client.admin().indices().prepareCreate("test").setSettings(ImmutableSettings.settingsBuilder().put("index.number_of_shards", 1)).execute().actionGet();
client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet();
client.admin().indices().preparePutMapping("test").setType("type1")
.setSource(XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
.startObject("foo").field("type", "string").endObject()
.startObject("bar").field("type", "integer").endObject()
.endObject().endObject().endObject())
.execute().actionGet();
client.admin().indices().prepareRefresh().execute().actionGet();
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery("foo".getBytes()).execute().actionGet().valid(), equalTo(false));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("_id:1")).execute().actionGet().valid(), equalTo(true));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("_i:d:1")).execute().actionGet().valid(), equalTo(false));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("foo:1")).execute().actionGet().valid(), equalTo(true));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("bar:hey")).execute().actionGet().valid(), equalTo(false));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("nonexistent:hello")).execute().actionGet().valid(), equalTo(true));
assertThat(client.admin().indices().prepareValidateQuery("test").setQuery(QueryBuilders.queryString("foo:1 AND")).execute().actionGet().valid(), equalTo(false));
}
}