mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-10 15:05:33 +00:00
Move templates out of the Search API, into lang-mustache module
This commit moves template support out of the Search API to its own dedicated Search Template API in the lang-mustache module. It provides a new SearchTemplateAction that can be used to render templates before it gets delegated to the usual Search API. The current REST endpoint are identical, but the Render Search Template endpoint now uses the same Search Template API with a new "simulate" option. When this option is enabled, the Search Template API only renders template and returns immediatly, without executing the search. Closes #17906
This commit is contained in:
parent
4be94cdc95
commit
04da1bda0d
@ -66,8 +66,6 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsAction;
|
||||
import org.elasticsearch.action.admin.cluster.stats.TransportClusterStatsAction;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksAction;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.TransportPendingClusterTasksAction;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateAction;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.TransportRenderSearchTemplateAction;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
|
||||
import org.elasticsearch.action.admin.indices.alias.TransportIndicesAliasesAction;
|
||||
import org.elasticsearch.action.admin.indices.alias.exists.AliasesExistAction;
|
||||
@ -340,7 +338,6 @@ public class ActionModule extends AbstractModule {
|
||||
registerAction(ExplainAction.INSTANCE, TransportExplainAction.class);
|
||||
registerAction(ClearScrollAction.INSTANCE, TransportClearScrollAction.class);
|
||||
registerAction(RecoveryAction.INSTANCE, TransportRecoveryAction.class);
|
||||
registerAction(RenderSearchTemplateAction.INSTANCE, TransportRenderSearchTemplateAction.class);
|
||||
|
||||
//Indexed scripts
|
||||
registerAction(PutStoredScriptAction.INSTANCE, TransportPutStoredScriptAction.class);
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.validate.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RenderSearchTemplateRequest extends ActionRequest<RenderSearchTemplateRequest> {
|
||||
|
||||
private Template template;
|
||||
|
||||
public void template(Template template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public Template template() {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException exception = null;
|
||||
if (template == null) {
|
||||
exception = new ActionRequestValidationException();
|
||||
exception.addValidationError("template must not be null");
|
||||
}
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
boolean hasTemplate = template!= null;
|
||||
out.writeBoolean(hasTemplate);
|
||||
if (hasTemplate) {
|
||||
template.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
if (in.readBoolean()) {
|
||||
template = new Template(in);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.validate.template;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class TransportRenderSearchTemplateAction extends HandledTransportAction<RenderSearchTemplateRequest, RenderSearchTemplateResponse> {
|
||||
|
||||
private final ScriptService scriptService;
|
||||
private final ClusterService clusterService;
|
||||
|
||||
@Inject
|
||||
public TransportRenderSearchTemplateAction(ScriptService scriptService, Settings settings, ThreadPool threadPool,
|
||||
TransportService transportService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
ClusterService clusterService) {
|
||||
super(settings, RenderSearchTemplateAction.NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, RenderSearchTemplateRequest::new);
|
||||
this.scriptService = scriptService;
|
||||
this.clusterService = clusterService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(final RenderSearchTemplateRequest request, final ActionListener<RenderSearchTemplateResponse> listener) {
|
||||
threadPool.generic().execute(new AbstractRunnable() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
listener.onFailure(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doRun() throws Exception {
|
||||
ExecutableScript executable = scriptService.executable(request.template(), ScriptContext.Standard.SEARCH,
|
||||
Collections.emptyMap(), clusterService.state());
|
||||
BytesReference processedTemplate = (BytesReference) executable.run();
|
||||
RenderSearchTemplateResponse response = new RenderSearchTemplateResponse();
|
||||
response.source(processedTemplate);
|
||||
listener.onResponse(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,6 @@ import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
||||
@ -71,8 +70,6 @@ public class SearchRequest extends ActionRequest<SearchRequest> implements Indic
|
||||
|
||||
private IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
|
||||
private Template template;
|
||||
|
||||
public SearchRequest() {
|
||||
}
|
||||
|
||||
@ -222,21 +219,6 @@ public class SearchRequest extends ActionRequest<SearchRequest> implements Indic
|
||||
return source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The stored template
|
||||
*/
|
||||
public void template(Template template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
/**
|
||||
* The stored template
|
||||
*/
|
||||
public Template template() {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tye of search to execute.
|
||||
*/
|
||||
@ -326,7 +308,6 @@ public class SearchRequest extends ActionRequest<SearchRequest> implements Indic
|
||||
indicesOptions = IndicesOptions.readIndicesOptions(in);
|
||||
|
||||
requestCache = in.readOptionalBoolean();
|
||||
template = in.readOptionalWriteable(Template::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -357,6 +338,5 @@ public class SearchRequest extends ActionRequest<SearchRequest> implements Indic
|
||||
out.writeStringArray(types);
|
||||
indicesOptions.writeIndicesOptions(out);
|
||||
out.writeOptionalBoolean(requestCache);
|
||||
out.writeOptionalWriteable(template);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.PipelineAggregationBuilder;
|
||||
@ -496,14 +495,6 @@ public class SearchRequestBuilder extends ActionRequestBuilder<SearchRequest, Se
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* template stuff
|
||||
*/
|
||||
public SearchRequestBuilder setTemplate(Template template) {
|
||||
request.template(template);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if this request should use the request cache or not, assuming that it can (for
|
||||
* example, if "now" is used, it will never be cached). By default (not set, or null,
|
||||
|
@ -99,9 +99,6 @@ import org.elasticsearch.action.admin.cluster.storedscripts.PutStoredScriptRespo
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksRequest;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksRequestBuilder;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksResponse;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateRequest;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateResponse;
|
||||
import org.elasticsearch.action.ingest.DeletePipelineRequest;
|
||||
import org.elasticsearch.action.ingest.DeletePipelineRequestBuilder;
|
||||
import org.elasticsearch.action.ingest.GetPipelineRequest;
|
||||
@ -536,28 +533,6 @@ public interface ClusterAdminClient extends ElasticsearchClient {
|
||||
*/
|
||||
SnapshotsStatusRequestBuilder prepareSnapshotStatus();
|
||||
|
||||
|
||||
/**
|
||||
* Return the rendered search request for a given search template.
|
||||
*
|
||||
* @param request The request
|
||||
* @return The result future
|
||||
*/
|
||||
ActionFuture<RenderSearchTemplateResponse> renderSearchTemplate(RenderSearchTemplateRequest request);
|
||||
|
||||
/**
|
||||
* Return the rendered search request for a given search template.
|
||||
*
|
||||
* @param request The request
|
||||
* @param listener A listener to be notified of the result
|
||||
*/
|
||||
void renderSearchTemplate(RenderSearchTemplateRequest request, ActionListener<RenderSearchTemplateResponse> listener);
|
||||
|
||||
/**
|
||||
* Return the rendered search request for a given search template.
|
||||
*/
|
||||
RenderSearchTemplateRequestBuilder prepareRenderSearchTemplate();
|
||||
|
||||
/**
|
||||
* Stores an ingest pipeline
|
||||
*/
|
||||
|
@ -129,10 +129,6 @@ import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksAction;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksRequest;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksRequestBuilder;
|
||||
import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksResponse;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateAction;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateRequest;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateResponse;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesAction;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
|
||||
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequestBuilder;
|
||||
@ -1073,21 +1069,6 @@ public abstract class AbstractClient extends AbstractComponent implements Client
|
||||
return new SnapshotsStatusRequestBuilder(this, SnapshotsStatusAction.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionFuture<RenderSearchTemplateResponse> renderSearchTemplate(final RenderSearchTemplateRequest request) {
|
||||
return execute(RenderSearchTemplateAction.INSTANCE, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderSearchTemplate(final RenderSearchTemplateRequest request, final ActionListener<RenderSearchTemplateResponse> listener) {
|
||||
execute(RenderSearchTemplateAction.INSTANCE, request, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderSearchTemplateRequestBuilder prepareRenderSearchTemplate() {
|
||||
return new RenderSearchTemplateRequestBuilder(this, RenderSearchTemplateAction.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putPipeline(PutPipelineRequest request, ActionListener<WritePipelineResponse> listener) {
|
||||
execute(PutPipelineAction.INSTANCE, request, listener);
|
||||
|
@ -66,11 +66,8 @@ import org.elasticsearch.rest.action.admin.cluster.snapshots.restore.RestRestore
|
||||
import org.elasticsearch.rest.action.admin.cluster.snapshots.status.RestSnapshotsStatusAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.state.RestClusterStateAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.stats.RestClusterStatsAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteStoredScriptAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetStoredScriptAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutStoredScriptAction;
|
||||
import org.elasticsearch.rest.action.admin.cluster.tasks.RestPendingClusterTasksAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.RestRolloverIndexAction;
|
||||
@ -108,7 +105,6 @@ import org.elasticsearch.rest.action.admin.indices.template.head.RestHeadIndexTe
|
||||
import org.elasticsearch.rest.action.admin.indices.template.put.RestPutIndexTemplateAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.upgrade.RestUpgradeAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.validate.query.RestValidateQueryAction;
|
||||
import org.elasticsearch.rest.action.admin.indices.validate.template.RestRenderSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.bulk.RestBulkAction;
|
||||
import org.elasticsearch.rest.action.cat.AbstractCatAction;
|
||||
import org.elasticsearch.rest.action.cat.RestAliasAction;
|
||||
@ -256,7 +252,6 @@ public class NetworkModule extends AbstractModule {
|
||||
RestSearchScrollAction.class,
|
||||
RestClearScrollAction.class,
|
||||
RestMultiSearchAction.class,
|
||||
RestRenderSearchTemplateAction.class,
|
||||
|
||||
RestValidateQueryAction.class,
|
||||
|
||||
@ -264,11 +259,6 @@ public class NetworkModule extends AbstractModule {
|
||||
|
||||
RestRecoveryAction.class,
|
||||
|
||||
// Templates API
|
||||
RestGetSearchTemplateAction.class,
|
||||
RestPutSearchTemplateAction.class,
|
||||
RestDeleteSearchTemplateAction.class,
|
||||
|
||||
// Scripts API
|
||||
RestGetStoredScriptAction.class,
|
||||
RestPutStoredScriptAction.class,
|
||||
@ -359,6 +349,10 @@ public class NetworkModule extends AbstractModule {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTransportClient() {
|
||||
return transportClient;
|
||||
}
|
||||
|
||||
/** Adds a transport service implementation that can be selected by setting {@link #TRANSPORT_SERVICE_TYPE_KEY}. */
|
||||
public void registerTransportService(String name, Class<? extends TransportService> clazz) {
|
||||
transportServiceTypes.registerExtension(name, clazz);
|
||||
|
@ -426,6 +426,7 @@ public final class ObjectParser<Value, Context extends ParseFieldMatcherSupplier
|
||||
OBJECT(START_OBJECT),
|
||||
OBJECT_ARRAY(START_OBJECT, START_ARRAY),
|
||||
OBJECT_OR_BOOLEAN(START_OBJECT, VALUE_BOOLEAN),
|
||||
OBJECT_OR_STRING(START_OBJECT, VALUE_STRING),
|
||||
VALUE(VALUE_BOOLEAN, VALUE_NULL, VALUE_EMBEDDED_OBJECT, VALUE_NUMBER, VALUE_STRING);
|
||||
|
||||
private final EnumSet<XContentParser.Token> tokens;
|
||||
|
@ -1048,10 +1048,6 @@ public class IndicesService extends AbstractLifecycleComponent<IndicesService>
|
||||
* Can the shard request be cached at all?
|
||||
*/
|
||||
public boolean canCache(ShardSearchRequest request, SearchContext context) {
|
||||
if (request.template() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// for now, only enable it for requests with no hits
|
||||
if (context.size() != 0) {
|
||||
return false;
|
||||
|
@ -43,21 +43,6 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
|
||||
if (registerDefaultHandlers) {
|
||||
controller.registerHandler(POST, "/_scripts/{lang}/{id}", this);
|
||||
controller.registerHandler(PUT, "/_scripts/{lang}/{id}", this);
|
||||
|
||||
controller.registerHandler(PUT, "/_scripts/{lang}/{id}/_create", new CreateHandler(settings, controller, client));
|
||||
controller.registerHandler(POST, "/_scripts/{lang}/{id}/_create", new CreateHandler(settings, controller, client));
|
||||
}
|
||||
}
|
||||
|
||||
final class CreateHandler extends BaseRestHandler {
|
||||
protected CreateHandler(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(RestRequest request, RestChannel channel, final Client client) {
|
||||
request.params().put("op_type", "create");
|
||||
RestPutStoredScriptAction.this.handleRequest(request, channel, client);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,5 +56,4 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
|
||||
putRequest.script(request.content());
|
||||
client.admin().cluster().putStoredScript(putRequest, new AcknowledgedRestListener<>(channel));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.rest.action.admin.indices.validate.template;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateRequest;
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.BytesRestResponse;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.RestResponse;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestBuilderListener;
|
||||
import org.elasticsearch.script.Script.ScriptField;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.rest.RestStatus.OK;
|
||||
|
||||
public class RestRenderSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Inject
|
||||
public RestRenderSearchTemplateAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
controller.registerHandler(GET, "/_render/template", this);
|
||||
controller.registerHandler(POST, "/_render/template", this);
|
||||
controller.registerHandler(GET, "/_render/template/{id}", this);
|
||||
controller.registerHandler(POST, "/_render/template/{id}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
RenderSearchTemplateRequest renderSearchTemplateRequest;
|
||||
BytesReference source = RestActions.getRestContent(request);
|
||||
try (XContentParser parser = XContentFactory.xContent(source).createParser(source)) {
|
||||
String templateId = request.param("id");
|
||||
final Template template;
|
||||
if (templateId == null) {
|
||||
template = Template.parse(parser, parseFieldMatcher);
|
||||
} else {
|
||||
Map<String, Object> params = null;
|
||||
String currentFieldName = null;
|
||||
XContentParser.Token token = parser.nextToken();
|
||||
if (token != XContentParser.Token.START_OBJECT) {
|
||||
throw new ElasticsearchParseException("failed to parse request. request body must be an object but found [{}] instead",
|
||||
token);
|
||||
}
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptField.PARAMS)) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
params = parser.map();
|
||||
} else {
|
||||
throw new ElasticsearchParseException(
|
||||
"failed to parse request. field [{}] is expected to be an object, but found [{}] instead",
|
||||
currentFieldName, token);
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("failed to parse request. unknown field [{}] of type [{}]", currentFieldName,
|
||||
token);
|
||||
}
|
||||
}
|
||||
template = new Template(templateId, ScriptType.STORED, Template.DEFAULT_LANG, null, params);
|
||||
}
|
||||
renderSearchTemplateRequest = new RenderSearchTemplateRequest();
|
||||
renderSearchTemplateRequest.template(template);
|
||||
}
|
||||
client.admin().cluster().renderSearchTemplate(renderSearchTemplateRequest, new RestBuilderListener<RenderSearchTemplateResponse>(channel) {
|
||||
|
||||
@Override
|
||||
public RestResponse buildResponse(RenderSearchTemplateResponse response, XContentBuilder builder) throws Exception {
|
||||
builder.prettyPrint();
|
||||
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
return new BytesRestResponse(OK, builder);
|
||||
}});
|
||||
}
|
||||
}
|
@ -19,19 +19,11 @@
|
||||
|
||||
package org.elasticsearch.rest.action.search;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue;
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringArrayValue;
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringValue;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.MultiSearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
@ -41,7 +33,6 @@ import org.elasticsearch.common.xcontent.XContent;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
@ -49,11 +40,20 @@ import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestToXContentListener;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue;
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringArrayValue;
|
||||
import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringValue;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class RestMultiSearchAction extends BaseRestHandler {
|
||||
@ -77,48 +77,55 @@ public class RestMultiSearchAction extends BaseRestHandler {
|
||||
controller.registerHandler(GET, "/{index}/{type}/_msearch", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_msearch", this);
|
||||
|
||||
controller.registerHandler(GET, "/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/_msearch/template", this);
|
||||
controller.registerHandler(GET, "/{index}/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/{index}/_msearch/template", this);
|
||||
controller.registerHandler(GET, "/{index}/{type}/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_msearch/template", this);
|
||||
|
||||
this.allowExplicitIndex = MULTI_ALLOW_EXPLICIT_INDEX.get(settings);
|
||||
this.indicesQueriesRegistry = indicesQueriesRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws Exception {
|
||||
MultiSearchRequest multiSearchRequest = new MultiSearchRequest();
|
||||
if (request.hasParam("max_concurrent_searches")) {
|
||||
multiSearchRequest.maxConcurrentSearchRequests(request.paramAsInt("max_concurrent_searches", 0));
|
||||
}
|
||||
|
||||
String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
|
||||
String[] types = Strings.splitStringByCommaToArray(request.param("type"));
|
||||
String path = request.path();
|
||||
boolean isTemplateRequest = isTemplateRequest(path);
|
||||
IndicesOptions indicesOptions = IndicesOptions.fromRequest(request, multiSearchRequest.indicesOptions());
|
||||
parseRequest(multiSearchRequest, RestActions.getRestContent(request), isTemplateRequest, indices, types,
|
||||
request.param("search_type"), request.param("routing"), indicesOptions, allowExplicitIndex, indicesQueriesRegistry,
|
||||
parseFieldMatcher, aggParsers, suggesters);
|
||||
MultiSearchRequest multiSearchRequest = parseRequest(request, allowExplicitIndex, indicesQueriesRegistry, parseFieldMatcher,
|
||||
aggParsers, suggesters);
|
||||
client.multiSearch(multiSearchRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
private boolean isTemplateRequest(String path) {
|
||||
return (path != null && path.endsWith("/template"));
|
||||
/**
|
||||
* Parses a {@link RestRequest} body and returns a {@link MultiSearchRequest}
|
||||
*/
|
||||
public static MultiSearchRequest parseRequest(RestRequest restRequest, boolean allowExplicitIndex,
|
||||
IndicesQueriesRegistry queriesRegistry, ParseFieldMatcher parseFieldMatcher,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters) throws IOException {
|
||||
|
||||
MultiSearchRequest multiRequest = new MultiSearchRequest();
|
||||
if (restRequest.hasParam("max_concurrent_searches")) {
|
||||
multiRequest.maxConcurrentSearchRequests(restRequest.paramAsInt("max_concurrent_searches", 0));
|
||||
}
|
||||
|
||||
parseMultiLineRequest(restRequest, multiRequest.indicesOptions(), allowExplicitIndex, (searchRequest, bytes) -> {
|
||||
try (XContentParser requestParser = XContentFactory.xContent(bytes).createParser(bytes)) {
|
||||
final QueryParseContext queryParseContext = new QueryParseContext(queriesRegistry, requestParser, parseFieldMatcher);
|
||||
searchRequest.source(SearchSourceBuilder.fromXContent(queryParseContext, aggParsers, suggesters));
|
||||
multiRequest.add(searchRequest);
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchParseException("Exception when parsing search request", e);
|
||||
}
|
||||
});
|
||||
|
||||
return multiRequest;
|
||||
}
|
||||
|
||||
public static MultiSearchRequest parseRequest(MultiSearchRequest msr, BytesReference data, boolean isTemplateRequest,
|
||||
@Nullable String[] indices,
|
||||
@Nullable String[] types,
|
||||
@Nullable String searchType,
|
||||
@Nullable String routing,
|
||||
IndicesOptions indicesOptions,
|
||||
boolean allowExplicitIndex, IndicesQueriesRegistry indicesQueriesRegistry,
|
||||
ParseFieldMatcher parseFieldMatcher, AggregatorParsers aggParsers,
|
||||
Suggesters suggesters) throws Exception {
|
||||
/**
|
||||
* Parses a multi-line {@link RestRequest} body, instanciating a {@link SearchRequest} for each line and applying the given consumer.
|
||||
*/
|
||||
public static void parseMultiLineRequest(RestRequest request, IndicesOptions indicesOptions, boolean allowExplicitIndex,
|
||||
BiConsumer<SearchRequest, BytesReference> consumer) throws IOException {
|
||||
|
||||
String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
|
||||
String[] types = Strings.splitStringByCommaToArray(request.param("type"));
|
||||
String searchType = request.param("search_type");
|
||||
String routing = request.param("routing");
|
||||
|
||||
final BytesReference data = RestActions.getRestContent(request);
|
||||
|
||||
XContent xContent = XContentFactory.xContent(data);
|
||||
int from = 0;
|
||||
int length = data.length();
|
||||
@ -147,7 +154,9 @@ public class RestMultiSearchAction extends BaseRestHandler {
|
||||
if (routing != null) {
|
||||
searchRequest.routing(routing);
|
||||
}
|
||||
searchRequest.searchType(searchType);
|
||||
if (searchType != null) {
|
||||
searchRequest.searchType(searchType);
|
||||
}
|
||||
|
||||
IndicesOptions defaultOptions = IndicesOptions.strictExpandOpenAndForbidClosed();
|
||||
|
||||
@ -187,26 +196,10 @@ public class RestMultiSearchAction extends BaseRestHandler {
|
||||
if (nextMarker == -1) {
|
||||
break;
|
||||
}
|
||||
final BytesReference slice = data.slice(from, nextMarker - from);
|
||||
if (isTemplateRequest) {
|
||||
try (XContentParser parser = XContentFactory.xContent(slice).createParser(slice)) {
|
||||
final QueryParseContext queryParseContext = new QueryParseContext(indicesQueriesRegistry, parser, parseFieldMatcher);
|
||||
Template template = TemplateQueryBuilder.parse(parser, queryParseContext.getParseFieldMatcher(), "params", "template");
|
||||
searchRequest.template(template);
|
||||
}
|
||||
} else {
|
||||
try (XContentParser requestParser = XContentFactory.xContent(slice).createParser(slice)) {
|
||||
final QueryParseContext queryParseContext = new QueryParseContext(indicesQueriesRegistry, requestParser,
|
||||
parseFieldMatcher);
|
||||
searchRequest.source(SearchSourceBuilder.fromXContent(queryParseContext, aggParsers, suggesters));
|
||||
}
|
||||
}
|
||||
consumer.accept(searchRequest, data.slice(from, nextMarker - from));
|
||||
// move pointers
|
||||
from = nextMarker + 1;
|
||||
|
||||
msr.add(searchRequest);
|
||||
}
|
||||
return msr;
|
||||
}
|
||||
|
||||
private static int findNextMarker(byte marker, int from, BytesReference data, int length) {
|
||||
|
@ -33,7 +33,6 @@ import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
@ -41,7 +40,6 @@ import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestStatusToXContentListener;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
@ -82,18 +80,13 @@ public class RestSearchAction extends BaseRestHandler {
|
||||
controller.registerHandler(POST, "/{index}/_search", this);
|
||||
controller.registerHandler(GET, "/{index}/{type}/_search", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_search", this);
|
||||
controller.registerHandler(GET, "/_search/template", this);
|
||||
controller.registerHandler(POST, "/_search/template", this);
|
||||
controller.registerHandler(GET, "/{index}/_search/template", this);
|
||||
controller.registerHandler(POST, "/{index}/_search/template", this);
|
||||
controller.registerHandler(GET, "/{index}/{type}/_search/template", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_search/template", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) throws IOException {
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
parseSearchRequest(searchRequest, queryRegistry, request, parseFieldMatcher, aggParsers, suggesters, null);
|
||||
BytesReference restContent = RestActions.hasBodyContent(request) ? RestActions.getRestContent(request) : null;
|
||||
parseSearchRequest(searchRequest, queryRegistry, request, parseFieldMatcher, aggParsers, suggesters, restContent);
|
||||
client.search(searchRequest, new RestStatusToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
@ -114,23 +107,10 @@ public class RestSearchAction extends BaseRestHandler {
|
||||
searchRequest.source(new SearchSourceBuilder());
|
||||
}
|
||||
searchRequest.indices(Strings.splitStringByCommaToArray(request.param("index")));
|
||||
// get the content, and put it in the body
|
||||
// add content/source as template if template flag is set
|
||||
boolean isTemplateRequest = request.path().endsWith("/template");
|
||||
if (restContent == null) {
|
||||
if (RestActions.hasBodyContent(request)) {
|
||||
restContent = RestActions.getRestContent(request);
|
||||
}
|
||||
}
|
||||
if (restContent != null) {
|
||||
try (XContentParser parser = XContentFactory.xContent(restContent).createParser(restContent)) {
|
||||
QueryParseContext context = new QueryParseContext(indicesQueriesRegistry, parser, parseFieldMatcher);
|
||||
if (isTemplateRequest) {
|
||||
Template template = TemplateQueryBuilder.parse(parser, context.getParseFieldMatcher(), "params", "template");
|
||||
searchRequest.template(template);
|
||||
} else {
|
||||
searchRequest.source().parseXContent(context, aggParsers, suggesters);
|
||||
}
|
||||
searchRequest.source().parseXContent(context, aggParsers, suggesters);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
@ -58,20 +57,17 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.Index;
|
||||
import org.elasticsearch.index.IndexService;
|
||||
import org.elasticsearch.index.engine.Engine;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.InnerHitBuilder;
|
||||
import org.elasticsearch.index.shard.IndexEventListener;
|
||||
import org.elasticsearch.index.shard.IndexShard;
|
||||
import org.elasticsearch.index.shard.SearchOperationListener;
|
||||
import org.elasticsearch.indices.IndicesService;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.SearchScript;
|
||||
import org.elasticsearch.search.aggregations.AggregationInitializationException;
|
||||
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.aggregations.SearchContextAggregations;
|
||||
import org.elasticsearch.search.aggregations.support.AggregationContext;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
@ -103,7 +99,6 @@ import org.elasticsearch.search.rescore.RescoreBuilder;
|
||||
import org.elasticsearch.search.searchafter.SearchAfterBuilder;
|
||||
import org.elasticsearch.search.sort.SortAndFormats;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
||||
import com.carrotsearch.hppc.ObjectFloatHashMap;
|
||||
@ -153,16 +148,11 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> imp
|
||||
private final Map<String, SearchParseElement> elementParsers;
|
||||
|
||||
private final ParseFieldMatcher parseFieldMatcher;
|
||||
private final AggregatorParsers aggParsers;
|
||||
private final Suggesters suggesters;
|
||||
|
||||
@Inject
|
||||
public SearchService(Settings settings, ClusterSettings clusterSettings, ClusterService clusterService, IndicesService indicesService,
|
||||
ThreadPool threadPool, ScriptService scriptService, BigArrays bigArrays,
|
||||
FetchPhase fetchPhase, AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
ThreadPool threadPool, ScriptService scriptService, BigArrays bigArrays, FetchPhase fetchPhase) {
|
||||
super(settings);
|
||||
this.aggParsers = aggParsers;
|
||||
this.suggesters = suggesters;
|
||||
this.parseFieldMatcher = new ParseFieldMatcher(settings);
|
||||
this.threadPool = threadPool;
|
||||
this.clusterService = clusterService;
|
||||
@ -556,16 +546,6 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> imp
|
||||
context.scrollContext(new ScrollContext());
|
||||
context.scrollContext().scroll = request.scroll();
|
||||
}
|
||||
if (request.template() != null) {
|
||||
ExecutableScript executable = this.scriptService.executable(request.template(), ScriptContext.Standard.SEARCH,
|
||||
Collections.emptyMap(), context.getQueryShardContext().getClusterState());
|
||||
BytesReference run = (BytesReference) executable.run();
|
||||
try (XContentParser parser = XContentFactory.xContent(run).createParser(run)) {
|
||||
QueryParseContext queryParseContext = new QueryParseContext(indicesService.getIndicesQueryRegistry(), parser,
|
||||
parseFieldMatcher);
|
||||
parseSource(context, SearchSourceBuilder.fromXContent(queryParseContext, aggParsers, suggesters));
|
||||
}
|
||||
}
|
||||
parseSource(context, request.source());
|
||||
|
||||
// if the from and size are still not set, default them
|
||||
|
@ -29,7 +29,6 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
||||
@ -66,7 +65,6 @@ public class ShardSearchLocalRequest implements ShardSearchRequest {
|
||||
private String[] types = Strings.EMPTY_ARRAY;
|
||||
private String[] filteringAliases;
|
||||
private SearchSourceBuilder source;
|
||||
private Template template;
|
||||
private Boolean requestCache;
|
||||
private long nowInMillis;
|
||||
|
||||
@ -79,7 +77,6 @@ public class ShardSearchLocalRequest implements ShardSearchRequest {
|
||||
String[] filteringAliases, long nowInMillis) {
|
||||
this(shardRouting.shardId(), numberOfShards, searchRequest.searchType(),
|
||||
searchRequest.source(), searchRequest.types(), searchRequest.requestCache());
|
||||
this.template = searchRequest.template();
|
||||
this.scroll = searchRequest.scroll();
|
||||
this.filteringAliases = filteringAliases;
|
||||
this.nowInMillis = nowInMillis;
|
||||
@ -145,10 +142,6 @@ public class ShardSearchLocalRequest implements ShardSearchRequest {
|
||||
public long nowInMillis() {
|
||||
return nowInMillis;
|
||||
}
|
||||
@Override
|
||||
public Template template() {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean requestCache() {
|
||||
@ -183,7 +176,6 @@ public class ShardSearchLocalRequest implements ShardSearchRequest {
|
||||
types = in.readStringArray();
|
||||
filteringAliases = in.readStringArray();
|
||||
nowInMillis = in.readVLong();
|
||||
template = in.readOptionalWriteable(Template::new);
|
||||
requestCache = in.readOptionalBoolean();
|
||||
}
|
||||
|
||||
@ -211,8 +203,6 @@ public class ShardSearchLocalRequest implements ShardSearchRequest {
|
||||
if (!asKey) {
|
||||
out.writeVLong(nowInMillis);
|
||||
}
|
||||
|
||||
out.writeOptionalWriteable(template);
|
||||
out.writeOptionalBoolean(requestCache);
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
||||
@ -52,8 +51,6 @@ public interface ShardSearchRequest {
|
||||
|
||||
long nowInMillis();
|
||||
|
||||
Template template();
|
||||
|
||||
Boolean requestCache();
|
||||
|
||||
Scroll scroll();
|
||||
|
@ -30,7 +30,6 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.transport.TransportRequest;
|
||||
@ -113,10 +112,6 @@ public class ShardSearchTransportRequest extends TransportRequest implements Sha
|
||||
public long nowInMillis() {
|
||||
return shardSearchLocalRequest.nowInMillis();
|
||||
}
|
||||
@Override
|
||||
public Template template() {
|
||||
return shardSearchLocalRequest.template();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean requestCache() {
|
||||
|
@ -21,6 +21,7 @@ package org.elasticsearch.action.search;
|
||||
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
@ -28,21 +29,21 @@ import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParser;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.StreamsUtils;
|
||||
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class MultiSearchRequestTests extends ESTestCase {
|
||||
public void testSimpleAdd() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/simple-msearch1.json");
|
||||
MultiSearchRequest request = RestMultiSearchAction.parseRequest(new MultiSearchRequest(), new BytesArray(data), false, null, null,
|
||||
null, null, IndicesOptions.strictExpandOpenAndForbidClosed(), true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
MultiSearchRequest request = parseMultiSearchRequest("/org/elasticsearch/action/search/simple-msearch1.json");
|
||||
assertThat(request.requests().size(), equalTo(8));
|
||||
assertThat(request.requests().get(0).indices()[0], equalTo("test"));
|
||||
assertThat(request.requests().get(0).indicesOptions(), equalTo(IndicesOptions.fromOptions(true, true, true, true, IndicesOptions.strictExpandOpenAndForbidClosed())));
|
||||
@ -56,37 +57,33 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||
assertThat(request.requests().get(3).indicesOptions(), equalTo(IndicesOptions.fromOptions(true, true, true, true, IndicesOptions.strictExpandOpenAndForbidClosed())));
|
||||
assertThat(request.requests().get(4).indices()[0], equalTo("test"));
|
||||
assertThat(request.requests().get(4).indicesOptions(), equalTo(IndicesOptions.fromOptions(true, false, false, true, IndicesOptions.strictExpandOpenAndForbidClosed())));
|
||||
assertThat(request.requests().get(5).indices(), nullValue());
|
||||
assertThat(request.requests().get(5).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(5).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(6).indices(), nullValue());
|
||||
assertThat(request.requests().get(6).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(6).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(6).searchType(), equalTo(SearchType.DFS_QUERY_THEN_FETCH));
|
||||
assertThat(request.requests().get(7).indices(), nullValue());
|
||||
assertThat(request.requests().get(7).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(7).types().length, equalTo(0));
|
||||
}
|
||||
|
||||
public void testSimpleAdd2() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/simple-msearch2.json");
|
||||
MultiSearchRequest request = RestMultiSearchAction.parseRequest(new MultiSearchRequest(), new BytesArray(data), false, null, null,
|
||||
null, null, IndicesOptions.strictExpandOpenAndForbidClosed(), true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
MultiSearchRequest request = parseMultiSearchRequest("/org/elasticsearch/action/search/simple-msearch2.json");
|
||||
assertThat(request.requests().size(), equalTo(5));
|
||||
assertThat(request.requests().get(0).indices()[0], equalTo("test"));
|
||||
assertThat(request.requests().get(0).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(1).indices()[0], equalTo("test"));
|
||||
assertThat(request.requests().get(1).types()[0], equalTo("type1"));
|
||||
assertThat(request.requests().get(2).indices(), nullValue());
|
||||
assertThat(request.requests().get(2).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(2).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(3).indices(), nullValue());
|
||||
assertThat(request.requests().get(3).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(3).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(3).searchType(), equalTo(SearchType.DFS_QUERY_THEN_FETCH));
|
||||
assertThat(request.requests().get(4).indices(), nullValue());
|
||||
assertThat(request.requests().get(4).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(4).types().length, equalTo(0));
|
||||
}
|
||||
|
||||
public void testSimpleAdd3() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/simple-msearch3.json");
|
||||
MultiSearchRequest request = RestMultiSearchAction.parseRequest(new MultiSearchRequest(), new BytesArray(data), false, null, null,
|
||||
null, null, IndicesOptions.strictExpandOpenAndForbidClosed(), true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
MultiSearchRequest request = parseMultiSearchRequest("/org/elasticsearch/action/search/simple-msearch3.json");
|
||||
assertThat(request.requests().size(), equalTo(4));
|
||||
assertThat(request.requests().get(0).indices()[0], equalTo("test0"));
|
||||
assertThat(request.requests().get(0).indices()[1], equalTo("test1"));
|
||||
@ -97,15 +94,13 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||
assertThat(request.requests().get(2).indices()[1], equalTo("test1"));
|
||||
assertThat(request.requests().get(2).types()[0], equalTo("type2"));
|
||||
assertThat(request.requests().get(2).types()[1], equalTo("type1"));
|
||||
assertThat(request.requests().get(3).indices(), nullValue());
|
||||
assertThat(request.requests().get(3).indices(), is(Strings.EMPTY_ARRAY));
|
||||
assertThat(request.requests().get(3).types().length, equalTo(0));
|
||||
assertThat(request.requests().get(3).searchType(), equalTo(SearchType.DFS_QUERY_THEN_FETCH));
|
||||
}
|
||||
|
||||
public void testSimpleAdd4() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/simple-msearch4.json");
|
||||
MultiSearchRequest request = RestMultiSearchAction.parseRequest(new MultiSearchRequest(), new BytesArray(data), false, null, null,
|
||||
null, null, IndicesOptions.strictExpandOpenAndForbidClosed(), true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
MultiSearchRequest request = parseMultiSearchRequest("/org/elasticsearch/action/search/simple-msearch4.json");
|
||||
assertThat(request.requests().size(), equalTo(3));
|
||||
assertThat(request.requests().get(0).indices()[0], equalTo("test0"));
|
||||
assertThat(request.requests().get(0).indices()[1], equalTo("test1"));
|
||||
@ -123,39 +118,6 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||
assertThat(request.requests().get(2).routing(), equalTo("123"));
|
||||
}
|
||||
|
||||
public void testSimpleAdd5() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/simple-msearch5.json");
|
||||
MultiSearchRequest request = RestMultiSearchAction.parseRequest(new MultiSearchRequest(), new BytesArray(data), true, null, null,
|
||||
null, null, IndicesOptions.strictExpandOpenAndForbidClosed(), true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
assertThat(request.requests().size(), equalTo(3));
|
||||
assertThat(request.requests().get(0).indices()[0], equalTo("test0"));
|
||||
assertThat(request.requests().get(0).indices()[1], equalTo("test1"));
|
||||
assertThat(request.requests().get(0).requestCache(), equalTo(true));
|
||||
assertThat(request.requests().get(0).preference(), nullValue());
|
||||
assertThat(request.requests().get(1).indices()[0], equalTo("test2"));
|
||||
assertThat(request.requests().get(1).indices()[1], equalTo("test3"));
|
||||
assertThat(request.requests().get(1).types()[0], equalTo("type1"));
|
||||
assertThat(request.requests().get(1).requestCache(), nullValue());
|
||||
assertThat(request.requests().get(1).preference(), equalTo("_local"));
|
||||
assertThat(request.requests().get(2).indices()[0], equalTo("test4"));
|
||||
assertThat(request.requests().get(2).indices()[1], equalTo("test1"));
|
||||
assertThat(request.requests().get(2).types()[0], equalTo("type2"));
|
||||
assertThat(request.requests().get(2).types()[1], equalTo("type1"));
|
||||
assertThat(request.requests().get(2).routing(), equalTo("123"));
|
||||
assertNotNull(request.requests().get(0).template());
|
||||
assertNotNull(request.requests().get(1).template());
|
||||
assertNotNull(request.requests().get(2).template());
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(0).template().getType());
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(1).template().getType());
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(2).template().getType());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(0).template().getScript());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(1).template().getScript());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(2).template().getScript());
|
||||
assertEquals(1, request.requests().get(0).template().getParams().size());
|
||||
assertEquals(1, request.requests().get(1).template().getParams().size());
|
||||
assertEquals(1, request.requests().get(2).template().getParams().size());
|
||||
}
|
||||
|
||||
public void testResponseErrorToXContent() throws IOException {
|
||||
MultiSearchResponse response = new MultiSearchResponse(new MultiSearchResponse.Item[]{new MultiSearchResponse.Item(null, new IllegalStateException("foobar")), new MultiSearchResponse.Item(null, new IllegalStateException("baaaaaazzzz"))});
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder();
|
||||
@ -171,6 +133,12 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||
request.maxConcurrentSearchRequests(randomIntBetween(Integer.MIN_VALUE, 0)));
|
||||
}
|
||||
|
||||
private MultiSearchRequest parseMultiSearchRequest(String sample) throws IOException {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath(sample);
|
||||
RestRequest restRequest = new FakeRestRequest.Builder().withContent(new BytesArray(data)).build();
|
||||
return RestMultiSearchAction.parseRequest(restRequest, true, registry(), ParseFieldMatcher.EMPTY, null, null);
|
||||
}
|
||||
|
||||
private IndicesQueriesRegistry registry() {
|
||||
IndicesQueriesRegistry registry = new IndicesQueriesRegistry();
|
||||
QueryParser<MatchAllQueryBuilder> parser = MatchAllQueryBuilder::fromXContent;
|
||||
|
@ -115,11 +115,13 @@ public class NetworkModuleTests extends ModuleTestCase {
|
||||
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
|
||||
module.registerTransportService("custom", FakeTransportService.class);
|
||||
assertBinding(module, TransportService.class, FakeTransportService.class);
|
||||
assertFalse(module.isTransportClient());
|
||||
|
||||
// check it works with transport only as well
|
||||
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
|
||||
module.registerTransportService("custom", FakeTransportService.class);
|
||||
assertBinding(module, TransportService.class, FakeTransportService.class);
|
||||
assertTrue(module.isTransportClient());
|
||||
}
|
||||
|
||||
public void testRegisterTransport() {
|
||||
@ -127,11 +129,13 @@ public class NetworkModuleTests extends ModuleTestCase {
|
||||
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
|
||||
module.registerTransport("custom", FakeTransport.class);
|
||||
assertBinding(module, Transport.class, FakeTransport.class);
|
||||
assertFalse(module.isTransportClient());
|
||||
|
||||
// check it works with transport only as well
|
||||
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
|
||||
module.registerTransport("custom", FakeTransport.class);
|
||||
assertBinding(module, Transport.class, FakeTransport.class);
|
||||
assertTrue(module.isTransportClient());
|
||||
}
|
||||
|
||||
public void testRegisterHttpTransport() {
|
||||
@ -139,9 +143,11 @@ public class NetworkModuleTests extends ModuleTestCase {
|
||||
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
|
||||
module.registerHttpTransport("custom", FakeHttpTransport.class);
|
||||
assertBinding(module, HttpServerTransport.class, FakeHttpTransport.class);
|
||||
assertFalse(module.isTransportClient());
|
||||
|
||||
// check registration not allowed for transport only
|
||||
module = new NetworkModule(new NetworkService(settings), settings, true, new NamedWriteableRegistry());
|
||||
assertTrue(module.isTransportClient());
|
||||
try {
|
||||
module.registerHttpTransport("custom", FakeHttpTransport.class);
|
||||
fail();
|
||||
@ -154,6 +160,7 @@ public class NetworkModuleTests extends ModuleTestCase {
|
||||
settings = Settings.builder().put(NetworkModule.HTTP_ENABLED.getKey(), false).build();
|
||||
module = new NetworkModule(new NetworkService(settings), settings, false, new NamedWriteableRegistry());
|
||||
assertNotBound(module, HttpServerTransport.class);
|
||||
assertFalse(module.isTransportClient());
|
||||
}
|
||||
|
||||
public void testRegisterRestHandler() {
|
||||
@ -186,6 +193,7 @@ public class NetworkModuleTests extends ModuleTestCase {
|
||||
NamedWriteableRegistry registry = new NamedWriteableRegistry();
|
||||
Settings settings = Settings.EMPTY;
|
||||
NetworkModule module = new NetworkModule(new NetworkService(settings), settings, false, registry);
|
||||
assertFalse(module.isTransportClient());
|
||||
|
||||
// Builtin reader comes back
|
||||
assertNotNull(registry.getReader(Task.Status.class, ReplicationTask.Status.NAME));
|
||||
|
@ -29,7 +29,6 @@ import org.elasticsearch.common.util.BigArrays;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
@ -93,11 +92,6 @@ public class SearchSlowLogTests extends ESSingleNodeTestCase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Template template() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean requestCache() {
|
||||
return null;
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateResponse;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
@ -55,11 +54,6 @@ public class StoredScriptsIT extends ESIntegTestCase {
|
||||
assertNotNull(script);
|
||||
assertEquals("1", script);
|
||||
|
||||
RenderSearchTemplateResponse response = client().admin().cluster().prepareRenderSearchTemplate()
|
||||
.template(new Template("/" + LANG + "/foobar", ScriptService.ScriptType.STORED, LANG, null, null))
|
||||
.get();
|
||||
assertEquals("1", response.source().toUtf8());
|
||||
|
||||
assertAcked(client().admin().cluster().prepareDeleteStoredScript()
|
||||
.setId("foobar")
|
||||
.setScriptLang(LANG));
|
||||
|
@ -1,6 +0,0 @@
|
||||
{"index":["test0", "test1"], "request_cache": true}
|
||||
{"template": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } } }
|
||||
{"index" : "test2,test3", "type" : "type1", "preference": "_local"}
|
||||
{"template": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } } }
|
||||
{"index" : ["test4", "test1"], "type" : [ "type2", "type1" ], "routing": "123"}
|
||||
{"template": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } } }
|
@ -265,13 +265,14 @@ The `setTemplateSource(String)` and `setTemplateSource(BytesReference)` methods
|
||||
|
||||
==== SearchRequest
|
||||
|
||||
All `template` methods have been removed in favor of a single `template(Template)` method.
|
||||
|
||||
All `source` methods have been removed in favor of a single `source(SearchSourceBuilder)` method. This means that all search requests can now be validated
|
||||
at call time which results in much clearer errors.
|
||||
|
||||
All `extraSource` methods have been removed.
|
||||
|
||||
All `template` methods have been removed in favor of a new Search Template API. A new `SearchTemplateRequest` now accepts a template and
|
||||
a `SearchRequest` and must be executed using the new `SearchTemplateAction` action.
|
||||
|
||||
==== SearchResponse
|
||||
|
||||
Sort values for `string` fields are now return as `java.lang.String` objects rather than `org.elasticsearch.common.text.Text`.
|
||||
@ -310,3 +311,11 @@ Removed the `getMemoryAvailable` method from `OsStats`, which could be previousl
|
||||
`setRefresh(boolean)` has been removed in favor of `setRefreshPolicy(RefreshPolicy)` because there
|
||||
are now three options (NONE, IMMEDIATE, and WAIT_FOR). `setRefresh(IMMEDIATE)` has the same behavior
|
||||
as `setRefresh(true)` used to have. See `setRefreshPolicy`'s javadoc for more.
|
||||
|
||||
=== Render Search Template Java API has been removed
|
||||
|
||||
The Render Search Template Java API including `RenderSearchTemplateAction`, `RenderSearchTemplateRequest` and
|
||||
`RenderSearchTemplateResponse` has been removed in favor of a new `simulate` option in the Search Template Java API.
|
||||
This Search Template API is now included in the `lang-mustache` module and the `simulate` flag must be set on the
|
||||
`SearchTemplateRequest` object.
|
||||
|
||||
|
@ -62,3 +62,15 @@ renamed `filter`/`token_filter`/`char_filter`.
|
||||
|
||||
The `DELETE /_query` endpoint provided by the Delete-By-Query plugin has been
|
||||
removed and replaced by the <<docs-delete-by-query,Delete By Query API>>.
|
||||
|
||||
==== Create stored script endpoint removed
|
||||
|
||||
The `PUT /_scripts/{lang}/{id}/_create` endpoint that previously allowed to create
|
||||
indexed scripts has been removed. Indexed scripts have been replaced
|
||||
by <<modules-scripting-stored-scripts,stored scripts>>.
|
||||
|
||||
==== Create stored template endpoint removed
|
||||
|
||||
The `PUT /_search/template/{id}/_create` endpoint that previously allowed to create
|
||||
indexed template has been removed. Indexed templates have been replaced
|
||||
by <<pre-registered-templates, Pre-registered templates>>.
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
==== Indexed scripts and templates
|
||||
|
||||
Indexed scrips and templates have been replaced by <<modules-scripting-stored-scripts,stored scripts>>
|
||||
Indexed scripts and templates have been replaced by <<modules-scripting-stored-scripts,stored scripts>>
|
||||
which stores the scripts and templates in the cluster state instead of a dedicate `.scripts` index.
|
||||
|
||||
For the size of stored scripts there is a soft limit of 65535 bytes. If scripts exceed that size then
|
||||
|
@ -369,3 +369,52 @@ GET /_render/template/<template_name>
|
||||
}
|
||||
}
|
||||
------------------------------------------
|
||||
|
||||
[[multi-search-template]]
|
||||
== Multi Search Template
|
||||
|
||||
The multi search template API allows to execute several search template
|
||||
requests within the same API using the `_msearch/template` endpoint.
|
||||
|
||||
The format of the request is similar to the <<search-multi-search, Multi
|
||||
Search API>> format:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
header\n
|
||||
body\n
|
||||
header\n
|
||||
body\n
|
||||
--------------------------------------------------
|
||||
|
||||
The header part supports the same `index`, `types`, `search_type`,
|
||||
`preference`, and `routing` options as the usual Multi Search API.
|
||||
|
||||
The body includes a search template body request and supports inline,
|
||||
stored and file templates. Here is an example:
|
||||
|
||||
[source,js]
|
||||
--------------------------------------------------
|
||||
$ cat requests
|
||||
{"index": "test"}
|
||||
{"inline": {"query": {"match": {"user" : "{{username}}" }}}, "params": {"username": "john"}} <1>
|
||||
{"index": "_all", "types": "accounts"}
|
||||
{"inline": {"query": {"{{query_type}}": {"name": "{{name}}" }}}, "params": {"query_type": "match_phrase_prefix", "name": "Smith"}}
|
||||
{"index": "_all"}
|
||||
{"id": "template_1", "params": {"query_string": "search for these words" }} <2>
|
||||
{"types": "users"}
|
||||
{"file": "template_2", "params": {"field_name": "fullname", "field_value": "john smith" }} <3>
|
||||
|
||||
$ curl -XGET localhost:9200/_msearch/template --data-binary "@requests"; echo
|
||||
--------------------------------------------------
|
||||
<1> Inline search template request
|
||||
|
||||
<2> Search template request based on a stored template
|
||||
|
||||
<3> Search template request based on a file template
|
||||
|
||||
The response returns a `responses` array, which includes the search template
|
||||
response for each search template request matching its order in the original
|
||||
multi search template request. If there was a complete failure for that specific
|
||||
search template request, an object with `error` message will be returned in place
|
||||
of the actual search response.
|
||||
|
@ -30,5 +30,9 @@ integTest {
|
||||
cluster {
|
||||
setting 'script.inline', 'true'
|
||||
setting 'script.stored', 'true'
|
||||
|
||||
|
||||
File template = new File('src/test/resources/org/elasticsearch/messy/tests/config/scripts/template_1.mustache')
|
||||
extraConfigFile 'scripts/template_1.mustache', template
|
||||
}
|
||||
}
|
||||
|
@ -17,28 +17,28 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.validate.template;
|
||||
package org.elasticsearch.action.search.template;
|
||||
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
|
||||
public class RenderSearchTemplateAction extends Action<RenderSearchTemplateRequest, RenderSearchTemplateResponse, RenderSearchTemplateRequestBuilder> {
|
||||
public class MultiSearchTemplateAction
|
||||
extends Action<MultiSearchTemplateRequest, MultiSearchTemplateResponse, MultiSearchTemplateRequestBuilder> {
|
||||
|
||||
public static final RenderSearchTemplateAction INSTANCE = new RenderSearchTemplateAction();
|
||||
public static final String NAME = "cluster:admin/render/template/search";
|
||||
public static final MultiSearchTemplateAction INSTANCE = new MultiSearchTemplateAction();
|
||||
public static final String NAME = "indices:data/read/msearch/template";
|
||||
|
||||
public RenderSearchTemplateAction() {
|
||||
private MultiSearchTemplateAction() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderSearchTemplateRequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new RenderSearchTemplateRequestBuilder(client, this);
|
||||
public MultiSearchTemplateResponse newResponse() {
|
||||
return new MultiSearchTemplateResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderSearchTemplateResponse newResponse() {
|
||||
return new RenderSearchTemplateResponse();
|
||||
public MultiSearchTemplateRequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new MultiSearchTemplateRequestBuilder(client, this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.CompositeIndicesRequest;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
||||
public class MultiSearchTemplateRequest extends ActionRequest<MultiSearchTemplateRequest> implements CompositeIndicesRequest {
|
||||
|
||||
private List<SearchTemplateRequest> requests = new ArrayList<>();
|
||||
|
||||
private IndicesOptions indicesOptions = IndicesOptions.strictExpandOpenAndForbidClosed();
|
||||
|
||||
/**
|
||||
* Add a search template request to execute. Note, the order is important, the search response will be returned in the
|
||||
* same order as the search requests.
|
||||
*/
|
||||
public MultiSearchTemplateRequest add(SearchTemplateRequestBuilder request) {
|
||||
requests.add(request.request());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a search template request to execute. Note, the order is important, the search response will be returned in the
|
||||
* same order as the search requests.
|
||||
*/
|
||||
public MultiSearchTemplateRequest add(SearchTemplateRequest request) {
|
||||
requests.add(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<SearchTemplateRequest> requests() {
|
||||
return this.requests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends IndicesRequest> subRequests() {
|
||||
return requests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (requests.isEmpty()) {
|
||||
validationException = addValidationError("no requests added", validationException);
|
||||
}
|
||||
for (SearchTemplateRequest request : requests) {
|
||||
ActionRequestValidationException ex = request.validate();
|
||||
if (ex != null) {
|
||||
if (validationException == null) {
|
||||
validationException = new ActionRequestValidationException();
|
||||
}
|
||||
validationException.addValidationErrors(ex.validationErrors());
|
||||
}
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
public IndicesOptions indicesOptions() {
|
||||
return indicesOptions;
|
||||
}
|
||||
|
||||
public MultiSearchTemplateRequest indicesOptions(IndicesOptions indicesOptions) {
|
||||
this.indicesOptions = indicesOptions;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
requests = in.readStreamableList(SearchTemplateRequest::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeStreamableList(requests);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
|
||||
public class MultiSearchTemplateRequestBuilder
|
||||
extends ActionRequestBuilder<MultiSearchTemplateRequest, MultiSearchTemplateResponse, MultiSearchTemplateRequestBuilder> {
|
||||
|
||||
protected MultiSearchTemplateRequestBuilder(ElasticsearchClient client, MultiSearchTemplateAction action) {
|
||||
super(client, action, new MultiSearchTemplateRequest());
|
||||
}
|
||||
|
||||
public MultiSearchTemplateRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, MultiSearchTemplateAction.INSTANCE);
|
||||
}
|
||||
|
||||
public MultiSearchTemplateRequestBuilder add(SearchTemplateRequest request) {
|
||||
if (request.getRequest().indicesOptions() == IndicesOptions.strictExpandOpenAndForbidClosed()
|
||||
&& request().indicesOptions() != IndicesOptions.strictExpandOpenAndForbidClosed()) {
|
||||
request.getRequest().indicesOptions(request().indicesOptions());
|
||||
}
|
||||
|
||||
super.request.add(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiSearchTemplateRequestBuilder add(SearchTemplateRequestBuilder request) {
|
||||
if (request.request().getRequest().indicesOptions() == IndicesOptions.strictExpandOpenAndForbidClosed()
|
||||
&& request().indicesOptions() != IndicesOptions.strictExpandOpenAndForbidClosed()) {
|
||||
request.request().getRequest().indicesOptions(request().indicesOptions());
|
||||
}
|
||||
|
||||
super.request.add(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MultiSearchTemplateRequestBuilder setIndicesOptions(IndicesOptions indicesOptions) {
|
||||
request().indicesOptions(indicesOptions);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
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.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class MultiSearchTemplateResponse extends ActionResponse implements Iterable<MultiSearchTemplateResponse.Item>, ToXContent {
|
||||
|
||||
/**
|
||||
* A search template response item, holding the actual search template response, or an error message if it failed.
|
||||
*/
|
||||
public static class Item implements Streamable {
|
||||
private SearchTemplateResponse response;
|
||||
private Throwable throwable;
|
||||
|
||||
Item() {
|
||||
}
|
||||
|
||||
public Item(SearchTemplateResponse response, Throwable throwable) {
|
||||
this.response = response;
|
||||
this.throwable = throwable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is it a failed search?
|
||||
*/
|
||||
public boolean isFailure() {
|
||||
return throwable != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual failure message, null if its not a failure.
|
||||
*/
|
||||
@Nullable
|
||||
public String getFailureMessage() {
|
||||
return throwable == null ? null : throwable.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual search response, null if its a failure.
|
||||
*/
|
||||
@Nullable
|
||||
public SearchTemplateResponse getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
public static Item readItem(StreamInput in) throws IOException {
|
||||
Item item = new Item();
|
||||
item.readFrom(in);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
if (in.readBoolean()) {
|
||||
this.response = new SearchTemplateResponse();
|
||||
response.readFrom(in);
|
||||
} else {
|
||||
throwable = in.readThrowable();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
if (response != null) {
|
||||
out.writeBoolean(true);
|
||||
response.writeTo(out);
|
||||
} else {
|
||||
out.writeBoolean(false);
|
||||
out.writeThrowable(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public Throwable getFailure() {
|
||||
return throwable;
|
||||
}
|
||||
}
|
||||
|
||||
private Item[] items;
|
||||
|
||||
MultiSearchTemplateResponse() {
|
||||
}
|
||||
|
||||
public MultiSearchTemplateResponse(Item[] items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Item> iterator() {
|
||||
return Arrays.stream(items).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of responses, the order is the same as the one provided in the request.
|
||||
*/
|
||||
public Item[] getResponses() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
items = new Item[in.readVInt()];
|
||||
for (int i = 0; i < items.length; i++) {
|
||||
items[i] = Item.readItem(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeVInt(items.length);
|
||||
for (Item item : items) {
|
||||
item.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
builder.startArray(Fields.RESPONSES);
|
||||
for (Item item : items) {
|
||||
builder.startObject();
|
||||
if (item.isFailure()) {
|
||||
ElasticsearchException.renderThrowable(builder, params, item.getFailure());
|
||||
} else {
|
||||
item.getResponse().toXContent(builder, params);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endArray();
|
||||
return builder;
|
||||
}
|
||||
|
||||
static final class Fields {
|
||||
static final String RESPONSES = "responses";
|
||||
static final String ERROR = "error";
|
||||
static final String ROOT_CAUSE = "root_cause";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
XContentBuilder builder = XContentFactory.jsonBuilder().prettyPrint();
|
||||
builder.startObject();
|
||||
toXContent(builder, EMPTY_PARAMS);
|
||||
builder.endObject();
|
||||
return builder.string();
|
||||
} catch (IOException e) {
|
||||
return "{ \"error\" : \"" + e.getMessage() + "\"}";
|
||||
}
|
||||
}
|
||||
}
|
@ -17,26 +17,28 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.validate.template;
|
||||
package org.elasticsearch.action.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
public class RenderSearchTemplateRequestBuilder extends ActionRequestBuilder<RenderSearchTemplateRequest, RenderSearchTemplateResponse, RenderSearchTemplateRequestBuilder> {
|
||||
public class SearchTemplateAction extends Action<SearchTemplateRequest, SearchTemplateResponse, SearchTemplateRequestBuilder> {
|
||||
|
||||
public RenderSearchTemplateRequestBuilder(ElasticsearchClient client,
|
||||
RenderSearchTemplateAction action) {
|
||||
super(client, action, new RenderSearchTemplateRequest());
|
||||
}
|
||||
|
||||
public RenderSearchTemplateRequestBuilder template(Template template) {
|
||||
request.template(template);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Template template() {
|
||||
return request.template();
|
||||
public static final SearchTemplateAction INSTANCE = new SearchTemplateAction();
|
||||
public static final String NAME = "indices:data/read/search/template";
|
||||
|
||||
private SearchTemplateAction() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchTemplateRequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new SearchTemplateRequestBuilder(client, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchTemplateResponse newResponse() {
|
||||
return new SearchTemplateResponse();
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequest;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.IndicesRequest;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||
|
||||
/**
|
||||
* A request to execute a search based on a search template.
|
||||
*/
|
||||
public class SearchTemplateRequest extends ActionRequest<SearchTemplateRequest> implements IndicesRequest {
|
||||
|
||||
private SearchRequest request;
|
||||
private boolean simulate = false;
|
||||
private ScriptService.ScriptType scriptType;
|
||||
private String script;
|
||||
private Map<String, Object> scriptParams;
|
||||
|
||||
public SearchTemplateRequest() {
|
||||
}
|
||||
|
||||
public SearchTemplateRequest(SearchRequest searchRequest) {
|
||||
this.request = searchRequest;
|
||||
}
|
||||
|
||||
public void setRequest(SearchRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public SearchRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSimulate() {
|
||||
return simulate;
|
||||
}
|
||||
|
||||
public void setSimulate(boolean simulate) {
|
||||
this.simulate = simulate;
|
||||
}
|
||||
|
||||
public ScriptService.ScriptType getScriptType() {
|
||||
return scriptType;
|
||||
}
|
||||
|
||||
public void setScriptType(ScriptService.ScriptType scriptType) {
|
||||
this.scriptType = scriptType;
|
||||
}
|
||||
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
public void setScript(String script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
public Map<String, Object> getScriptParams() {
|
||||
return scriptParams;
|
||||
}
|
||||
|
||||
public void setScriptParams(Map<String, Object> scriptParams) {
|
||||
this.scriptParams = scriptParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
ActionRequestValidationException validationException = null;
|
||||
if (script == null || script.isEmpty()) {
|
||||
validationException = addValidationError("template is missing", validationException);
|
||||
}
|
||||
if (scriptType == null) {
|
||||
validationException = addValidationError("template's script type is missing", validationException);
|
||||
}
|
||||
if (simulate == false) {
|
||||
if (request == null) {
|
||||
validationException = addValidationError("search request is missing", validationException);
|
||||
} else {
|
||||
ActionRequestValidationException ex = request.validate();
|
||||
if (ex != null) {
|
||||
if (validationException == null) {
|
||||
validationException = new ActionRequestValidationException();
|
||||
}
|
||||
validationException.addValidationErrors(ex.validationErrors());
|
||||
}
|
||||
}
|
||||
}
|
||||
return validationException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
request = in.readOptionalStreamable(SearchRequest::new);
|
||||
simulate = in.readBoolean();
|
||||
scriptType = ScriptService.ScriptType.readFrom(in);
|
||||
script = in.readOptionalString();
|
||||
if (in.readBoolean()) {
|
||||
scriptParams = in.readMap();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeOptionalStreamable(request);
|
||||
out.writeBoolean(simulate);
|
||||
ScriptService.ScriptType.writeTo(scriptType, out);
|
||||
out.writeOptionalString(script);
|
||||
boolean hasParams = scriptParams != null;
|
||||
out.writeBoolean(hasParams);
|
||||
if (hasParams) {
|
||||
out.writeMap(scriptParams);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] indices() {
|
||||
return request != null ? request.indices() : Strings.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndicesOptions indicesOptions() {
|
||||
return request != null ? request.indicesOptions() : SearchRequest.DEFAULT_INDICES_OPTIONS;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SearchTemplateRequestBuilder
|
||||
extends ActionRequestBuilder<SearchTemplateRequest, SearchTemplateResponse, SearchTemplateRequestBuilder> {
|
||||
|
||||
SearchTemplateRequestBuilder(ElasticsearchClient client, SearchTemplateAction action) {
|
||||
super(client, action, new SearchTemplateRequest());
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder(ElasticsearchClient client) {
|
||||
this(client, SearchTemplateAction.INSTANCE);
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder setRequest(SearchRequest searchRequest) {
|
||||
request.setRequest(searchRequest);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder setSimulate(boolean simulate) {
|
||||
request.setSimulate(simulate);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder setScriptType(ScriptService.ScriptType scriptType) {
|
||||
request.setScriptType(scriptType);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder setScript(String script) {
|
||||
request.setScript(script);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchTemplateRequestBuilder setScriptParams(Map<String, Object> scriptParams) {
|
||||
request.setScriptParams(scriptParams);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -17,52 +17,80 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.action.admin.cluster.validate.template;
|
||||
package org.elasticsearch.action.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionResponse;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.StatusToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RenderSearchTemplateResponse extends ActionResponse implements ToXContent {
|
||||
public class SearchTemplateResponse extends ActionResponse implements StatusToXContent {
|
||||
|
||||
/** Contains the source of the rendered template **/
|
||||
private BytesReference source;
|
||||
|
||||
public BytesReference source() {
|
||||
/** Contains the search response, if any **/
|
||||
private SearchResponse response;
|
||||
|
||||
SearchTemplateResponse() {
|
||||
}
|
||||
|
||||
public BytesReference getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void source(BytesReference source) {
|
||||
|
||||
public void setSource(BytesReference source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public SearchResponse getResponse() {
|
||||
return response;
|
||||
}
|
||||
|
||||
public void setResponse(SearchResponse searchResponse) {
|
||||
this.response = searchResponse;
|
||||
}
|
||||
|
||||
public boolean hasResponse() {
|
||||
return response != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
boolean hasSource = source != null;
|
||||
out.writeBoolean(hasSource);
|
||||
if (hasSource) {
|
||||
out.writeBytesReference(source);
|
||||
}
|
||||
out.writeOptionalBytesReference(source);
|
||||
out.writeOptionalStreamable(response);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
if (in.readBoolean()) {
|
||||
source = in.readBytesReference();
|
||||
}
|
||||
source = in.readOptionalBytesReference();
|
||||
response = in.readOptionalStreamable(SearchResponse::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.rawField("template_output", source);
|
||||
builder.endObject();
|
||||
if (hasResponse()) {
|
||||
response.toXContent(builder, params);
|
||||
} else {
|
||||
builder.rawField("template_output", source);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestStatus status() {
|
||||
if (hasResponse()) {
|
||||
return response.status();
|
||||
} else {
|
||||
return RestStatus.OK;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.AtomicArray;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class TransportMultiSearchTemplateAction extends HandledTransportAction<MultiSearchTemplateRequest, MultiSearchTemplateResponse> {
|
||||
|
||||
private final TransportSearchTemplateAction searchTemplateAction;
|
||||
|
||||
@Inject
|
||||
public TransportMultiSearchTemplateAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver resolver,
|
||||
TransportSearchTemplateAction searchTemplateAction) {
|
||||
super(settings, MultiSearchTemplateAction.NAME, threadPool, transportService, actionFilters, resolver,
|
||||
MultiSearchTemplateRequest::new);
|
||||
this.searchTemplateAction = searchTemplateAction;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(MultiSearchTemplateRequest request, ActionListener<MultiSearchTemplateResponse> listener) {
|
||||
final AtomicArray<MultiSearchTemplateResponse.Item> responses = new AtomicArray<>(request.requests().size());
|
||||
final AtomicInteger counter = new AtomicInteger(responses.length());
|
||||
|
||||
for (int i = 0; i < responses.length(); i++) {
|
||||
final int index = i;
|
||||
searchTemplateAction.execute(request.requests().get(i), new ActionListener<SearchTemplateResponse>() {
|
||||
@Override
|
||||
public void onResponse(SearchTemplateResponse searchTemplateResponse) {
|
||||
responses.set(index, new MultiSearchTemplateResponse.Item(searchTemplateResponse, null));
|
||||
if (counter.decrementAndGet() == 0) {
|
||||
finishHim();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable e) {
|
||||
responses.set(index, new MultiSearchTemplateResponse.Item(null, e));
|
||||
if (counter.decrementAndGet() == 0) {
|
||||
finishHim();
|
||||
}
|
||||
}
|
||||
|
||||
private void finishHim() {
|
||||
MultiSearchTemplateResponse.Item[] items = responses.toArray(new MultiSearchTemplateResponse.Item[responses.length()]);
|
||||
listener.onResponse(new MultiSearchTemplateResponse(items));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.TransportSearchAction;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.elasticsearch.script.ScriptContext.Standard.SEARCH;
|
||||
|
||||
public class TransportSearchTemplateAction extends HandledTransportAction<SearchTemplateRequest, SearchTemplateResponse> {
|
||||
|
||||
private static final String TEMPLATE_LANG = MustacheScriptEngineService.NAME;
|
||||
|
||||
private final ClusterService clusterService;
|
||||
private final ScriptService scriptService;
|
||||
private final TransportSearchAction searchAction;
|
||||
private final IndicesQueriesRegistry queryRegistry;
|
||||
private final AggregatorParsers aggsParsers;
|
||||
private final Suggesters suggesters;
|
||||
|
||||
@Inject
|
||||
public TransportSearchTemplateAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
||||
ActionFilters actionFilters, IndexNameExpressionResolver resolver,
|
||||
ClusterService clusterService, ScriptService scriptService,
|
||||
TransportSearchAction searchAction, IndicesQueriesRegistry indicesQueryRegistry,
|
||||
AggregatorParsers aggregatorParsers, Suggesters suggesters) {
|
||||
super(settings, SearchTemplateAction.NAME, threadPool, transportService, actionFilters, resolver, SearchTemplateRequest::new);
|
||||
this.clusterService = clusterService;
|
||||
this.scriptService = scriptService;
|
||||
this.searchAction = searchAction;
|
||||
this.queryRegistry = indicesQueryRegistry;
|
||||
this.aggsParsers = aggregatorParsers;
|
||||
this.suggesters = suggesters;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(SearchTemplateRequest request, ActionListener<SearchTemplateResponse> listener) {
|
||||
final SearchTemplateResponse response = new SearchTemplateResponse();
|
||||
try {
|
||||
Script script = new Script(request.getScript(), request.getScriptType(), TEMPLATE_LANG, request.getScriptParams());
|
||||
ExecutableScript executable = scriptService.executable(script, SEARCH, emptyMap(), clusterService.state());
|
||||
|
||||
BytesReference source = (BytesReference) executable.run();
|
||||
response.setSource(source);
|
||||
|
||||
if (request.isSimulate()) {
|
||||
listener.onResponse(response);
|
||||
return;
|
||||
}
|
||||
|
||||
// Executes the search
|
||||
SearchRequest searchRequest = request.getRequest();
|
||||
|
||||
try (XContentParser parser = XContentFactory.xContent(source).createParser(source)) {
|
||||
SearchSourceBuilder builder = SearchSourceBuilder.searchSource();
|
||||
builder.parseXContent(new QueryParseContext(queryRegistry, parser, parseFieldMatcher), aggsParsers, suggesters);
|
||||
searchRequest.source(builder);
|
||||
|
||||
searchAction.execute(searchRequest, new ActionListener<SearchResponse>() {
|
||||
@Override
|
||||
public void onResponse(SearchResponse searchResponse) {
|
||||
try {
|
||||
response.setResponse(searchResponse);
|
||||
listener.onResponse(response);
|
||||
} catch (Throwable t) {
|
||||
listener.onFailure(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
listener.onFailure(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
listener.onFailure(t);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.rest.action.admin.cluster.storedscripts;
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
@ -16,7 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.rest.action.admin.cluster.storedscripts;
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
@ -28,11 +28,10 @@ import org.elasticsearch.script.Template;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RestGetSearchTemplateAction extends RestGetStoredScriptAction {
|
||||
|
||||
private static final String TEMPLATE = "template";
|
||||
|
||||
@Inject
|
||||
public RestGetSearchTemplateAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, controller, false, client);
|
||||
@ -48,6 +47,4 @@ public class RestGetSearchTemplateAction extends RestGetStoredScriptAction {
|
||||
protected String getScriptFieldName() {
|
||||
return TEMPLATE;
|
||||
}
|
||||
|
||||
private static final String TEMPLATE = "template";
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.template.MultiSearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.MultiSearchTemplateRequest;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestToXContentListener;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
|
||||
public class RestMultiSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
private final boolean allowExplicitIndex;
|
||||
|
||||
@Inject
|
||||
public RestMultiSearchTemplateAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
this.allowExplicitIndex = MULTI_ALLOW_EXPLICIT_INDEX.get(settings);
|
||||
|
||||
controller.registerHandler(GET, "/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/_msearch/template", this);
|
||||
controller.registerHandler(GET, "/{index}/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/{index}/_msearch/template", this);
|
||||
controller.registerHandler(GET, "/{index}/{type}/_msearch/template", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_msearch/template", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
if (RestActions.hasBodyContent(request) == false) {
|
||||
throw new ElasticsearchException("request body is required");
|
||||
}
|
||||
|
||||
MultiSearchTemplateRequest multiRequest = parseRequest(request, allowExplicitIndex);
|
||||
client.execute(MultiSearchTemplateAction.INSTANCE, multiRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a {@link RestRequest} body and returns a {@link MultiSearchTemplateRequest}
|
||||
*/
|
||||
public static MultiSearchTemplateRequest parseRequest(RestRequest restRequest, boolean allowExplicitIndex) throws IOException {
|
||||
|
||||
MultiSearchTemplateRequest multiRequest = new MultiSearchTemplateRequest();
|
||||
RestMultiSearchAction.parseMultiLineRequest(restRequest, multiRequest.indicesOptions(), allowExplicitIndex,
|
||||
(searchRequest, bytes) -> {
|
||||
try {
|
||||
SearchTemplateRequest searchTemplateRequest = RestSearchTemplateAction.parse(bytes);
|
||||
if (searchTemplateRequest.getScript() != null) {
|
||||
searchTemplateRequest.setRequest(searchRequest);
|
||||
multiRequest.add(searchTemplateRequest);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Malformed search template");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ElasticsearchParseException("Exception when parsing search template request", e);
|
||||
}
|
||||
});
|
||||
return multiRequest;
|
||||
}
|
||||
}
|
@ -16,47 +16,26 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.rest.action.admin.cluster.storedscripts;
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutStoredScriptAction;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RestPutSearchTemplateAction extends RestPutStoredScriptAction {
|
||||
|
||||
@Inject
|
||||
public RestPutSearchTemplateAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, controller, false, client);
|
||||
|
||||
//controller.registerHandler(GET, "/template", this);
|
||||
controller.registerHandler(POST, "/_search/template/{id}", this);
|
||||
controller.registerHandler(PUT, "/_search/template/{id}", this);
|
||||
|
||||
controller.registerHandler(PUT, "/_search/template/{id}/_create", new CreateHandler(settings, controller, client));
|
||||
controller.registerHandler(POST, "/_search/template/{id}/_create", new CreateHandler(settings, controller, client));
|
||||
}
|
||||
|
||||
final class CreateHandler extends BaseRestHandler {
|
||||
protected CreateHandler(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequest(RestRequest request, RestChannel channel, final Client client) {
|
||||
request.params().put("op_type", "create");
|
||||
RestPutSearchTemplateAction.this.handleRequest(request, channel, client);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.action.search.template.SearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestToXContentListener;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
|
||||
public class RestRenderSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
@Inject
|
||||
public RestRenderSearchTemplateAction(Settings settings, RestController controller, Client client) {
|
||||
super(settings, client);
|
||||
controller.registerHandler(GET, "/_render/template", this);
|
||||
controller.registerHandler(POST, "/_render/template", this);
|
||||
controller.registerHandler(GET, "/_render/template/{id}", this);
|
||||
controller.registerHandler(POST, "/_render/template/{id}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
// Creates the render template request
|
||||
SearchTemplateRequest renderRequest = RestSearchTemplateAction.parse(RestActions.getRestContent(request));
|
||||
renderRequest.setSimulate(true);
|
||||
|
||||
String id = request.param("id");
|
||||
if (id != null) {
|
||||
renderRequest.setScriptType(ScriptService.ScriptType.STORED);
|
||||
renderRequest.setScript(id);
|
||||
}
|
||||
|
||||
client.execute(SearchTemplateAction.INSTANCE, renderRequest, new RestToXContentListener<>(channel));
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.ParseFieldMatcherSupplier;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestChannel;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.rest.action.support.RestStatusToXContentListener;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
|
||||
public class RestSearchTemplateAction extends BaseRestHandler {
|
||||
|
||||
private static ObjectParser<SearchTemplateRequest, ParseFieldMatcherSupplier> PARSER;
|
||||
static {
|
||||
PARSER = new ObjectParser<>("search_template");
|
||||
PARSER.declareField((parser, request, s) ->
|
||||
request.setScriptParams(parser.map())
|
||||
, new ParseField("params"), ObjectParser.ValueType.OBJECT);
|
||||
PARSER.declareString((request, s) -> {
|
||||
request.setScriptType(ScriptService.ScriptType.FILE);
|
||||
request.setScript(s);
|
||||
}, new ParseField("file"));
|
||||
PARSER.declareString((request, s) -> {
|
||||
request.setScriptType(ScriptService.ScriptType.STORED);
|
||||
request.setScript(s);
|
||||
}, new ParseField("id"));
|
||||
PARSER.declareField((parser, request, value) -> {
|
||||
request.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||
try (XContentBuilder builder = XContentFactory.contentBuilder(parser.contentType())) {
|
||||
request.setScript(builder.copyCurrentStructure(parser).bytes().toUtf8());
|
||||
} catch (IOException e) {
|
||||
throw new ParsingException(parser.getTokenLocation(), "Could not parse inline template", e);
|
||||
}
|
||||
} else {
|
||||
request.setScript(parser.text());
|
||||
}
|
||||
}, new ParseField("inline", "template"), ObjectParser.ValueType.OBJECT_OR_STRING);
|
||||
}
|
||||
|
||||
private final IndicesQueriesRegistry queryRegistry;
|
||||
private final AggregatorParsers aggParsers;
|
||||
private final Suggesters suggesters;
|
||||
|
||||
@Inject
|
||||
public RestSearchTemplateAction(Settings settings, RestController controller, Client client, IndicesQueriesRegistry queryRegistry,
|
||||
AggregatorParsers aggregatorParsers, Suggesters suggesters) {
|
||||
super(settings, client);
|
||||
this.queryRegistry = queryRegistry;
|
||||
this.aggParsers = aggregatorParsers;
|
||||
this.suggesters = suggesters;
|
||||
|
||||
controller.registerHandler(GET, "/_search/template", this);
|
||||
controller.registerHandler(POST, "/_search/template", this);
|
||||
controller.registerHandler(GET, "/{index}/_search/template", this);
|
||||
controller.registerHandler(POST, "/{index}/_search/template", this);
|
||||
controller.registerHandler(GET, "/{index}/{type}/_search/template", this);
|
||||
controller.registerHandler(POST, "/{index}/{type}/_search/template", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
if (RestActions.hasBodyContent(request) == false) {
|
||||
throw new ElasticsearchException("request body is required");
|
||||
}
|
||||
|
||||
// Creates the search request with all required params
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
RestSearchAction.parseSearchRequest(searchRequest, queryRegistry, request, parseFieldMatcher, aggParsers, suggesters, null);
|
||||
|
||||
// Creates the search template request
|
||||
SearchTemplateRequest searchTemplateRequest = parse(RestActions.getRestContent(request));
|
||||
searchTemplateRequest.setRequest(searchRequest);
|
||||
|
||||
client.execute(SearchTemplateAction.INSTANCE, searchTemplateRequest, new RestStatusToXContentListener<>(channel));
|
||||
}
|
||||
|
||||
public static SearchTemplateRequest parse(BytesReference bytes) throws IOException {
|
||||
try (XContentParser parser = XContentHelper.createParser(bytes)) {
|
||||
return PARSER.parse(parser, new SearchTemplateRequest(), () -> ParseFieldMatcher.STRICT);
|
||||
}
|
||||
}
|
||||
}
|
@ -19,9 +19,21 @@
|
||||
|
||||
package org.elasticsearch.script.mustache;
|
||||
|
||||
import org.elasticsearch.action.ActionModule;
|
||||
import org.elasticsearch.action.search.template.MultiSearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.TransportMultiSearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.TransportSearchTemplateAction;
|
||||
import org.elasticsearch.common.network.NetworkModule;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.plugins.ScriptPlugin;
|
||||
import org.elasticsearch.rest.action.search.template.RestDeleteSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestGetSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestMultiSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestPutSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestRenderSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptEngineRegistry;
|
||||
import org.elasticsearch.script.ScriptEngineService;
|
||||
import org.elasticsearch.script.ScriptModule;
|
||||
@ -32,4 +44,20 @@ public class MustachePlugin extends Plugin implements ScriptPlugin {
|
||||
public ScriptEngineService getScriptEngineService(Settings settings) {
|
||||
return new MustacheScriptEngineService(settings);
|
||||
}
|
||||
|
||||
public void onModule(ActionModule module) {
|
||||
module.registerAction(SearchTemplateAction.INSTANCE, TransportSearchTemplateAction.class);
|
||||
module.registerAction(MultiSearchTemplateAction.INSTANCE, TransportMultiSearchTemplateAction.class);
|
||||
}
|
||||
|
||||
public void onModule(NetworkModule module) {
|
||||
if (module.isTransportClient() == false) {
|
||||
module.registerRestHandler(RestSearchTemplateAction.class);
|
||||
module.registerRestHandler(RestMultiSearchTemplateAction.class);
|
||||
module.registerRestHandler(RestGetSearchTemplateAction.class);
|
||||
module.registerRestHandler(RestPutSearchTemplateAction.class);
|
||||
module.registerRestHandler(RestDeleteSearchTemplateAction.class);
|
||||
module.registerRestHandler(RestRenderSearchTemplateAction.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.index.IndexNotFoundException;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.hamcrest.Matchers.arrayWithSize;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
public class MultiSearchTemplateIT extends ESIntegTestCase {
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> nodePlugins() {
|
||||
return Collections.singleton(MustachePlugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
|
||||
return nodePlugins();
|
||||
}
|
||||
|
||||
public void testBasic() throws Exception {
|
||||
createIndex("msearch");
|
||||
final int numDocs = randomIntBetween(10, 100);
|
||||
IndexRequestBuilder[] indexRequestBuilders = new IndexRequestBuilder[numDocs];
|
||||
for (int i = 0; i < numDocs; i++) {
|
||||
indexRequestBuilders[i] = client().prepareIndex("msearch", "test", String.valueOf(i))
|
||||
.setSource("odd", (i % 2 == 0), "group", (i % 3));
|
||||
}
|
||||
indexRandom(true, indexRequestBuilders);
|
||||
|
||||
final String template = jsonBuilder().startObject()
|
||||
.startObject("query")
|
||||
.startObject("{{query_type}}")
|
||||
.field("{{field_name}}", "{{field_value}}")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject().string();
|
||||
|
||||
MultiSearchTemplateRequest multiRequest = new MultiSearchTemplateRequest();
|
||||
|
||||
// Search #1
|
||||
SearchTemplateRequest search1 = new SearchTemplateRequest();
|
||||
search1.setRequest(new SearchRequest("msearch"));
|
||||
search1.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
search1.setScript(template);
|
||||
|
||||
Map<String, Object> params1 = new HashMap<>();
|
||||
params1.put("query_type", "match");
|
||||
params1.put("field_name", "odd");
|
||||
params1.put("field_value", true);
|
||||
search1.setScriptParams(params1);
|
||||
multiRequest.add(search1);
|
||||
|
||||
// Search #2 (Simulate is true)
|
||||
SearchTemplateRequest search2 = new SearchTemplateRequest();
|
||||
search2.setRequest(new SearchRequest("msearch"));
|
||||
search2.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
search2.setScript(template);
|
||||
search2.setSimulate(true);
|
||||
|
||||
Map<String, Object> params2 = new HashMap<>();
|
||||
params2.put("query_type", "match_phrase_prefix");
|
||||
params2.put("field_name", "message");
|
||||
params2.put("field_value", "quick brown f");
|
||||
search2.setScriptParams(params2);
|
||||
multiRequest.add(search2);
|
||||
|
||||
// Search #3
|
||||
SearchTemplateRequest search3 = new SearchTemplateRequest();
|
||||
search3.setRequest(new SearchRequest("msearch"));
|
||||
search3.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
search3.setScript(template);
|
||||
search3.setSimulate(false);
|
||||
|
||||
Map<String, Object> params3 = new HashMap<>();
|
||||
params3.put("query_type", "term");
|
||||
params3.put("field_name", "odd");
|
||||
params3.put("field_value", "false");
|
||||
search3.setScriptParams(params3);
|
||||
multiRequest.add(search3);
|
||||
|
||||
// Search #4 (Fail because of unknown index)
|
||||
SearchTemplateRequest search4 = new SearchTemplateRequest();
|
||||
search4.setRequest(new SearchRequest("unknown"));
|
||||
search4.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
search4.setScript(template);
|
||||
|
||||
Map<String, Object> params4 = new HashMap<>();
|
||||
params4.put("query_type", "match");
|
||||
params4.put("field_name", "group");
|
||||
params4.put("field_value", "test");
|
||||
search4.setScriptParams(params4);
|
||||
multiRequest.add(search4);
|
||||
|
||||
// Search #5 (Simulate is true)
|
||||
SearchTemplateRequest search5 = new SearchTemplateRequest();
|
||||
search5.setRequest(new SearchRequest("msearch"));
|
||||
search5.setScriptType(ScriptService.ScriptType.INLINE);
|
||||
search5.setScript("{{! ignore me }}{\"query\":{\"terms\":{\"group\":[{{#groups}}{{.}},{{/groups}}]}}}");
|
||||
search5.setSimulate(true);
|
||||
|
||||
Map<String, Object> params5 = new HashMap<>();
|
||||
params5.put("groups", Arrays.asList(1, 2, 3));
|
||||
search5.setScriptParams(params5);
|
||||
multiRequest.add(search5);
|
||||
|
||||
MultiSearchTemplateResponse response = client().execute(MultiSearchTemplateAction.INSTANCE, multiRequest).get();
|
||||
assertThat(response.getResponses(), arrayWithSize(5));
|
||||
|
||||
MultiSearchTemplateResponse.Item response1 = response.getResponses()[0];
|
||||
assertThat(response1.isFailure(), is(false));
|
||||
SearchTemplateResponse searchTemplateResponse1 = response1.getResponse();
|
||||
assertThat(searchTemplateResponse1.hasResponse(), is(true));
|
||||
assertHitCount(searchTemplateResponse1.getResponse(), (numDocs / 2) + (numDocs % 2));
|
||||
assertThat(searchTemplateResponse1.getSource().toUtf8(),
|
||||
equalTo("{\"query\":{\"match\":{\"odd\":\"true\"}}}"));
|
||||
|
||||
MultiSearchTemplateResponse.Item response2 = response.getResponses()[1];
|
||||
assertThat(response2.isFailure(), is(false));
|
||||
SearchTemplateResponse searchTemplateResponse2 = response2.getResponse();
|
||||
assertThat(searchTemplateResponse2.hasResponse(), is(false));
|
||||
assertThat(searchTemplateResponse2.getSource().toUtf8(),
|
||||
equalTo("{\"query\":{\"match_phrase_prefix\":{\"message\":\"quick brown f\"}}}"));
|
||||
|
||||
MultiSearchTemplateResponse.Item response3 = response.getResponses()[2];
|
||||
assertThat(response3.isFailure(), is(false));
|
||||
SearchTemplateResponse searchTemplateResponse3 = response3.getResponse();
|
||||
assertThat(searchTemplateResponse3.hasResponse(), is(true));
|
||||
assertHitCount(searchTemplateResponse3.getResponse(), (numDocs / 2));
|
||||
assertThat(searchTemplateResponse3.getSource().toUtf8(),
|
||||
equalTo("{\"query\":{\"term\":{\"odd\":\"false\"}}}"));
|
||||
|
||||
MultiSearchTemplateResponse.Item response4 = response.getResponses()[3];
|
||||
assertThat(response4.isFailure(), is(true));
|
||||
assertThat(response4.getFailure(), instanceOf(IndexNotFoundException.class));
|
||||
assertThat(response4.getFailure().getMessage(), equalTo("no such index"));
|
||||
|
||||
MultiSearchTemplateResponse.Item response5 = response.getResponses()[4];
|
||||
assertThat(response5.isFailure(), is(false));
|
||||
SearchTemplateResponse searchTemplateResponse5 = response5.getResponse();
|
||||
assertThat(searchTemplateResponse5.hasResponse(), is(false));
|
||||
assertThat(searchTemplateResponse5.getSource().toUtf8(),
|
||||
equalTo("{\"query\":{\"terms\":{\"group\":[1,2,3,]}}}"));
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.search.template.RestMultiSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.StreamsUtils;
|
||||
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class MultiSearchTemplateRequestTests extends ESTestCase {
|
||||
|
||||
public void testParseRequest() throws Exception {
|
||||
byte[] data = StreamsUtils.copyToBytesFromClasspath("/org/elasticsearch/action/search/template/simple-msearch-template.json");
|
||||
RestRequest restRequest = new FakeRestRequest.Builder().withContent(new BytesArray(data)).build();
|
||||
|
||||
MultiSearchTemplateRequest request = RestMultiSearchTemplateAction.parseRequest(restRequest, true);
|
||||
|
||||
assertThat(request.requests().size(), equalTo(3));
|
||||
assertThat(request.requests().get(0).getRequest().indices()[0], equalTo("test0"));
|
||||
assertThat(request.requests().get(0).getRequest().indices()[1], equalTo("test1"));
|
||||
assertThat(request.requests().get(0).indices(), arrayContaining("test0", "test1"));
|
||||
assertThat(request.requests().get(0).getRequest().requestCache(), equalTo(true));
|
||||
assertThat(request.requests().get(0).getRequest().preference(), nullValue());
|
||||
assertThat(request.requests().get(1).indices()[0], equalTo("test2"));
|
||||
assertThat(request.requests().get(1).indices()[1], equalTo("test3"));
|
||||
assertThat(request.requests().get(1).getRequest().types()[0], equalTo("type1"));
|
||||
assertThat(request.requests().get(1).getRequest().requestCache(), nullValue());
|
||||
assertThat(request.requests().get(1).getRequest().preference(), equalTo("_local"));
|
||||
assertThat(request.requests().get(2).indices()[0], equalTo("test4"));
|
||||
assertThat(request.requests().get(2).indices()[1], equalTo("test1"));
|
||||
assertThat(request.requests().get(2).getRequest().types()[0], equalTo("type2"));
|
||||
assertThat(request.requests().get(2).getRequest().types()[1], equalTo("type1"));
|
||||
assertThat(request.requests().get(2).getRequest().routing(), equalTo("123"));
|
||||
assertNotNull(request.requests().get(0).getScript());
|
||||
assertNotNull(request.requests().get(1).getScript());
|
||||
assertNotNull(request.requests().get(2).getScript());
|
||||
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(0).getScriptType());
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(1).getScriptType());
|
||||
assertEquals(ScriptService.ScriptType.INLINE, request.requests().get(2).getScriptType());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(0).getScript());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(1).getScript());
|
||||
assertEquals("{\"query\":{\"match_{{template}}\":{}}}", request.requests().get(2).getScript());
|
||||
assertEquals(1, request.requests().get(0).getScriptParams().size());
|
||||
assertEquals(1, request.requests().get(1).getScriptParams().size());
|
||||
assertEquals(1, request.requests().get(2).getScriptParams().size());
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.search.template;
|
||||
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.rest.action.search.template.RestSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.hasItems;
|
||||
import static org.hamcrest.Matchers.hasKey;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class SearchTemplateRequestTests extends ESTestCase {
|
||||
|
||||
public void testParseInlineTemplate() throws Exception {
|
||||
String source = "{" +
|
||||
" 'inline' : {\n" +
|
||||
" 'query': {\n" +
|
||||
" 'terms': {\n" +
|
||||
" 'status': [\n" +
|
||||
" '{{#status}}',\n" +
|
||||
" '{{.}}',\n" +
|
||||
" '{{/status}}'\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("{\"query\":{\"terms\":{\"status\":[\"{{#status}}\",\"{{.}}\",\"{{/status}}\"]}}}"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.INLINE));
|
||||
assertThat(request.getScriptParams(), nullValue());
|
||||
}
|
||||
|
||||
public void testParseInlineTemplateWithParams() throws Exception {
|
||||
String source = "{" +
|
||||
" 'inline' : {" +
|
||||
" 'query': { 'match' : { '{{my_field}}' : '{{my_value}}' } }," +
|
||||
" 'size' : '{{my_size}}'" +
|
||||
" }," +
|
||||
" 'params' : {" +
|
||||
" 'my_field' : 'foo'," +
|
||||
" 'my_value' : 'bar'," +
|
||||
" 'my_size' : 5" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("{\"query\":{\"match\":{\"{{my_field}}\":\"{{my_value}}\"}},\"size\":\"{{my_size}}\"}"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.INLINE));
|
||||
assertThat(request.getScriptParams().size(), equalTo(3));
|
||||
assertThat(request.getScriptParams(), hasEntry("my_field", "foo"));
|
||||
assertThat(request.getScriptParams(), hasEntry("my_value", "bar"));
|
||||
assertThat(request.getScriptParams(), hasEntry("my_size", 5));
|
||||
}
|
||||
|
||||
public void testParseInlineTemplateAsString() throws Exception {
|
||||
String source = "{'inline' : '{\\\"query\\\":{\\\"bool\\\":{\\\"must\\\":{\\\"match\\\":{\\\"foo\\\":\\\"{{text}}\\\"}}}}}'}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("{\"query\":{\"bool\":{\"must\":{\"match\":{\"foo\":\"{{text}}\"}}}}}"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.INLINE));
|
||||
assertThat(request.getScriptParams(), nullValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testParseInlineTemplateAsStringWithParams() throws Exception {
|
||||
String source = "{'inline' : '{\\\"query\\\":{\\\"match\\\":{\\\"{{field}}\\\":\\\"{{value}}\\\"}}}', " +
|
||||
"'params': {'status': ['pending', 'published']}}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("{\"query\":{\"match\":{\"{{field}}\":\"{{value}}\"}}}"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.INLINE));
|
||||
assertThat(request.getScriptParams().size(), equalTo(1));
|
||||
assertThat(request.getScriptParams(), hasKey("status"));
|
||||
assertThat((List<String>) request.getScriptParams().get("status"), hasItems("pending", "published"));
|
||||
}
|
||||
|
||||
public void testParseFileTemplate() throws Exception {
|
||||
String source = "{'file' : 'fileTemplate'}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("fileTemplate"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.FILE));
|
||||
assertThat(request.getScriptParams(), nullValue());
|
||||
}
|
||||
|
||||
public void testParseFileTemplateWithParams() throws Exception {
|
||||
String source = "{'file' : 'template_foo', 'params' : {'foo': 'bar', 'size': 500}}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("template_foo"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.FILE));
|
||||
assertThat(request.getScriptParams().size(), equalTo(2));
|
||||
assertThat(request.getScriptParams(), hasEntry("foo", "bar"));
|
||||
assertThat(request.getScriptParams(), hasEntry("size", 500));
|
||||
}
|
||||
|
||||
public void testParseStoredTemplate() throws Exception {
|
||||
String source = "{'id' : 'storedTemplate'}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("storedTemplate"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.STORED));
|
||||
assertThat(request.getScriptParams(), nullValue());
|
||||
}
|
||||
|
||||
public void testParseStoredTemplateWithParams() throws Exception {
|
||||
String source = "{'id' : 'another_template', 'params' : {'bar': 'foo'}}";
|
||||
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(newBytesReference(source));
|
||||
assertThat(request.getScript(), equalTo("another_template"));
|
||||
assertThat(request.getScriptType(), equalTo(ScriptService.ScriptType.STORED));
|
||||
assertThat(request.getScriptParams().size(), equalTo(1));
|
||||
assertThat(request.getScriptParams(), hasEntry("bar", "foo"));
|
||||
}
|
||||
|
||||
public void testParseWrongTemplate() {
|
||||
// Unclosed template id
|
||||
expectThrows(ParsingException.class, () -> RestSearchTemplateAction.parse(newBytesReference("{'id' : 'another_temp }")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link BytesReference} with the given string while replacing single quote to double quotes.
|
||||
*/
|
||||
private static BytesReference newBytesReference(String s) {
|
||||
assertNotNull(s);
|
||||
return new BytesArray(s.replace("'", "\""));
|
||||
}
|
||||
}
|
@ -19,16 +19,15 @@
|
||||
|
||||
package org.elasticsearch.messy.tests;
|
||||
|
||||
import org.elasticsearch.action.admin.cluster.validate.template.RenderSearchTemplateResponse;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateResponse;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
@ -40,6 +39,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
@ -53,6 +53,11 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
return Collections.singleton(MustachePlugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
|
||||
return nodePlugins();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupSuiteScopeCluster() throws Exception {
|
||||
ElasticsearchAssertions.assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||
@ -75,14 +80,14 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
.put(Environment.PATH_CONF_SETTING.getKey(), configDir).build();
|
||||
}
|
||||
|
||||
public void testInlineTemplate() {
|
||||
public void testInlineTemplate() throws ExecutionException, InterruptedException {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("value", "bar");
|
||||
params.put("size", 20);
|
||||
Template template = new Template(TEMPLATE_CONTENTS, ScriptType.INLINE, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
RenderSearchTemplateResponse response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
SearchTemplateResponse response = prepareRenderSearchTemplate(TEMPLATE_CONTENTS, ScriptType.INLINE, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
BytesReference source = response.source();
|
||||
assertFalse(response.hasResponse());
|
||||
BytesReference source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
assertThat(sourceAsMap, notNullValue());
|
||||
@ -93,10 +98,10 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
params = new HashMap<>();
|
||||
params.put("value", "baz");
|
||||
params.put("size", 100);
|
||||
template = new Template(TEMPLATE_CONTENTS, ScriptType.INLINE, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
response = prepareRenderSearchTemplate(TEMPLATE_CONTENTS, ScriptType.INLINE, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
source = response.source();
|
||||
assertFalse(response.hasResponse());
|
||||
source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
expected = TEMPLATE_CONTENTS.replace("{{value}}", "baz").replace("{{size}}", "100");
|
||||
@ -104,14 +109,14 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
assertThat(sourceAsMap, equalTo(expectedMap));
|
||||
}
|
||||
|
||||
public void testIndexedTemplate() {
|
||||
public void testIndexedTemplate() throws ExecutionException, InterruptedException {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("value", "bar");
|
||||
params.put("size", 20);
|
||||
Template template = new Template("index_template_1", ScriptType.STORED, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
RenderSearchTemplateResponse response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
SearchTemplateResponse response = prepareRenderSearchTemplate("index_template_1", ScriptType.STORED, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
BytesReference source = response.source();
|
||||
assertFalse(response.hasResponse());
|
||||
BytesReference source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
assertThat(sourceAsMap, notNullValue());
|
||||
@ -122,10 +127,9 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
params = new HashMap<>();
|
||||
params.put("value", "baz");
|
||||
params.put("size", 100);
|
||||
template = new Template("index_template_1", ScriptType.STORED, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
response = prepareRenderSearchTemplate("index_template_1", ScriptType.STORED, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
source = response.source();
|
||||
source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
expected = TEMPLATE_CONTENTS.replace("{{value}}", "baz").replace("{{size}}", "100");
|
||||
@ -133,14 +137,14 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
assertThat(sourceAsMap, equalTo(expectedMap));
|
||||
}
|
||||
|
||||
public void testFileTemplate() {
|
||||
public void testFileTemplate() throws ExecutionException, InterruptedException {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("value", "bar");
|
||||
params.put("size", 20);
|
||||
Template template = new Template("file_template_1", ScriptType.FILE, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
RenderSearchTemplateResponse response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
SearchTemplateResponse response = prepareRenderSearchTemplate("file_template_1", ScriptType.FILE, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
BytesReference source = response.source();
|
||||
assertFalse(response.hasResponse());
|
||||
BytesReference source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
assertThat(sourceAsMap, notNullValue());
|
||||
@ -151,14 +155,17 @@ public class RenderSearchTemplateTests extends ESIntegTestCase {
|
||||
params = new HashMap<>();
|
||||
params.put("value", "baz");
|
||||
params.put("size", 100);
|
||||
template = new Template("file_template_1", ScriptType.FILE, MustacheScriptEngineService.NAME, XContentType.JSON, params);
|
||||
response = client().admin().cluster().prepareRenderSearchTemplate().template(template).get();
|
||||
response = prepareRenderSearchTemplate("file_template_1", ScriptType.FILE, params).get();
|
||||
assertThat(response, notNullValue());
|
||||
source = response.source();
|
||||
source = response.getSource();
|
||||
assertThat(source, notNullValue());
|
||||
sourceAsMap = XContentHelper.convertToMap(source, false).v2();
|
||||
expected = TEMPLATE_CONTENTS.replace("{{value}}", "baz").replace("{{size}}", "100");
|
||||
expectedMap = XContentHelper.convertToMap(new BytesArray(expected), false).v2();
|
||||
assertThat(sourceAsMap, equalTo(expectedMap));
|
||||
}
|
||||
|
||||
private SearchTemplateRequestBuilder prepareRenderSearchTemplate(String script, ScriptType type, Map<String, Object> params) {
|
||||
return new SearchTemplateRequestBuilder(client()).setScript(script).setScriptType(type).setScriptParams(params).setSimulate(true);
|
||||
}
|
||||
}
|
||||
|
@ -18,20 +18,16 @@
|
||||
*/
|
||||
package org.elasticsearch.messy.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse;
|
||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateAction;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequest;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateRequestBuilder;
|
||||
import org.elasticsearch.action.search.template.SearchTemplateResponse;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.ParsingException;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
@ -40,6 +36,7 @@ import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.rest.action.search.template.RestSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
@ -49,9 +46,16 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
@ -69,6 +73,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
return Collections.singleton(MustachePlugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
|
||||
return nodePlugins();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
createIndex("test");
|
||||
@ -142,11 +151,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indices("_all");
|
||||
|
||||
String query = "{ \"template\" : { \"query\": {\"match_{{template}}\": {} } }, \"params\" : { \"template\":\"all\" } }";
|
||||
searchRequest.template(parseTemplate(query));
|
||||
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertHitCount(searchResponse, 2);
|
||||
String query = "{ \"inline\" : { \"query\": {\"match_{{template}}\": {} } }, \"params\" : { \"template\":\"all\" } }";
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(new BytesArray(query));
|
||||
request.setRequest(searchRequest);
|
||||
SearchTemplateResponse response = client().execute(SearchTemplateAction.INSTANCE, request).get();
|
||||
assertHitCount(response.getResponse(), 2);
|
||||
}
|
||||
|
||||
private Template parseTemplate(String template) throws IOException {
|
||||
@ -155,23 +164,28 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
// Releates to #6318
|
||||
// Relates to #6318
|
||||
public void testSearchRequestFail() throws Exception {
|
||||
String query = "{ \"query\": {\"match_all\": {}}, \"size\" : \"{{my_size}}\" }";
|
||||
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indices("_all");
|
||||
try {
|
||||
String query = "{ \"template\" : { \"query\": {\"match_all\": {}}, \"size\" : \"{{my_size}}\" } }";
|
||||
searchRequest.template(parseTemplate(query));
|
||||
client().search(searchRequest).get();
|
||||
fail("expected exception");
|
||||
} catch (Exception ex) {
|
||||
// expected - no params
|
||||
}
|
||||
String query = "{ \"template\" : { \"query\": {\"match_all\": {}}, \"size\" : \"{{my_size}}\" }, \"params\" : { \"my_size\": 1 } }";
|
||||
searchRequest.template(parseTemplate(query));
|
||||
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertThat(searchResponse.getHits().hits().length, equalTo(1));
|
||||
expectThrows(Exception.class, () -> new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(searchRequest)
|
||||
.setScript(query)
|
||||
.setScriptType(ScriptType.INLINE)
|
||||
.setScriptParams(randomBoolean() ? null : Collections.emptyMap())
|
||||
.get());
|
||||
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(searchRequest)
|
||||
.setScript(query)
|
||||
.setScriptType(ScriptType.INLINE)
|
||||
.setScriptParams(Collections.singletonMap("my_size", 1))
|
||||
.get();
|
||||
|
||||
assertThat(searchResponse.getResponse().getHits().hits().length, equalTo(1));
|
||||
}
|
||||
|
||||
public void testThatParametersCanBeSet() throws Exception {
|
||||
@ -187,18 +201,24 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
templateParams.put("myField", "theField");
|
||||
templateParams.put("myValue", "foo");
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test").setTypes("type")
|
||||
.setTemplate(new Template("full-query-template", ScriptType.FILE, MustacheScriptEngineService.NAME, null, templateParams))
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("full-query-template")
|
||||
.setScriptType(ScriptType.FILE)
|
||||
.setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse, 4);
|
||||
assertHitCount(searchResponse.getResponse(), 4);
|
||||
// size kicks in here...
|
||||
assertThat(searchResponse.getHits().getHits().length, is(2));
|
||||
assertThat(searchResponse.getResponse().getHits().getHits().length, is(2));
|
||||
|
||||
templateParams.put("myField", "otherField");
|
||||
searchResponse = client().prepareSearch("test").setTypes("type")
|
||||
.setTemplate(new Template("full-query-template", ScriptType.FILE, MustacheScriptEngineService.NAME, null, templateParams))
|
||||
searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("full-query-template")
|
||||
.setScriptType(ScriptType.FILE)
|
||||
.setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertHitCount(searchResponse.getResponse(), 1);
|
||||
}
|
||||
|
||||
public void testSearchTemplateQueryFromFile() throws Exception {
|
||||
@ -206,9 +226,10 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
searchRequest.indices("_all");
|
||||
String query = "{" + " \"file\": \"full-query-template\"," + " \"params\":{" + " \"mySize\": 2,"
|
||||
+ " \"myField\": \"text\"," + " \"myValue\": \"value1\"" + " }" + "}";
|
||||
searchRequest.template(parseTemplate(query));
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertThat(searchResponse.getHits().hits().length, equalTo(1));
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(new BytesArray(query));
|
||||
request.setRequest(searchRequest);
|
||||
SearchTemplateResponse searchResponse = client().execute(SearchTemplateAction.INSTANCE, request).get();
|
||||
assertThat(searchResponse.getResponse().getHits().hits().length, equalTo(1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,11 +238,12 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
public void testTemplateQueryAsEscapedString() throws Exception {
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indices("_all");
|
||||
String query = "{" + " \"template\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\","
|
||||
String query = "{" + " \"inline\" : \"{ \\\"size\\\": \\\"{{size}}\\\", \\\"query\\\":{\\\"match_all\\\":{}}}\","
|
||||
+ " \"params\":{" + " \"size\": 1" + " }" + "}";
|
||||
searchRequest.template(parseTemplate(query));
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertThat(searchResponse.getHits().hits().length, equalTo(1));
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(new BytesArray(query));
|
||||
request.setRequest(searchRequest);
|
||||
SearchTemplateResponse searchResponse = client().execute(SearchTemplateAction.INSTANCE, request).get();
|
||||
assertThat(searchResponse.getResponse().getHits().hits().length, equalTo(1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -232,11 +254,12 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indices("_all");
|
||||
String templateString = "{"
|
||||
+ " \"template\" : \"{ {{#use_size}} \\\"size\\\": \\\"{{size}}\\\", {{/use_size}} \\\"query\\\":{\\\"match_all\\\":{}}}\","
|
||||
+ " \"inline\" : \"{ {{#use_size}} \\\"size\\\": \\\"{{size}}\\\", {{/use_size}} \\\"query\\\":{\\\"match_all\\\":{}}}\","
|
||||
+ " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}";
|
||||
searchRequest.template(parseTemplate(templateString));
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertThat(searchResponse.getHits().hits().length, equalTo(1));
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(new BytesArray(templateString));
|
||||
request.setRequest(searchRequest);
|
||||
SearchTemplateResponse searchResponse = client().execute(SearchTemplateAction.INSTANCE, request).get();
|
||||
assertThat(searchResponse.getResponse().getHits().hits().length, equalTo(1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,9 +272,10 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
String templateString = "{"
|
||||
+ " \"inline\" : \"{ \\\"query\\\":{\\\"match_all\\\":{}} {{#use_size}}, \\\"size\\\": \\\"{{size}}\\\" {{/use_size}} }\","
|
||||
+ " \"params\":{" + " \"size\": 1," + " \"use_size\": true" + " }" + "}";
|
||||
searchRequest.template(parseTemplate(templateString));
|
||||
SearchResponse searchResponse = client().search(searchRequest).get();
|
||||
assertThat(searchResponse.getHits().hits().length, equalTo(1));
|
||||
SearchTemplateRequest request = RestSearchTemplateAction.parse(new BytesArray(templateString));
|
||||
request.setRequest(searchRequest);
|
||||
SearchTemplateResponse searchResponse = client().execute(SearchTemplateAction.INSTANCE, request).get();
|
||||
assertThat(searchResponse.getResponse().getHits().hits().length, equalTo(1));
|
||||
}
|
||||
|
||||
public void testIndexedTemplateClient() throws Exception {
|
||||
@ -296,10 +320,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
templateParams.put("fieldParam", "foo");
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test").setTypes("type")
|
||||
.setTemplate(new Template("testTemplate", ScriptType.STORED, MustacheScriptEngineService.NAME, null, templateParams))
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("testTemplate").setScriptType(ScriptType.STORED).setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse, 4);
|
||||
assertHitCount(searchResponse.getResponse(), 4);
|
||||
|
||||
assertAcked(client().admin().cluster()
|
||||
.prepareDeleteStoredScript(MustacheScriptEngineService.NAME, "testTemplate"));
|
||||
@ -308,16 +333,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
.prepareGetStoredScript(MustacheScriptEngineService.NAME, "testTemplate").get();
|
||||
assertNull(getResponse.getStoredScript());
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/template_index/mustache/1000", ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
templateParams)).get();
|
||||
fail("Expected SearchPhaseExecutionException");
|
||||
} catch (SearchPhaseExecutionException e) {
|
||||
assertThat(e.toString(), containsString("Illegal index script format"));
|
||||
}
|
||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("/template_index/mustache/1000").setScriptType(ScriptType.STORED).setScriptParams(templateParams)
|
||||
.get());
|
||||
assertThat(e.getMessage(), containsString("Illegal index script format [/template_index/mustache/1000] should be /lang/id"));
|
||||
}
|
||||
|
||||
public void testIndexedTemplate() throws Exception {
|
||||
@ -357,8 +377,6 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
"}"))
|
||||
);
|
||||
|
||||
|
||||
|
||||
List<IndexRequestBuilder> builders = new ArrayList<>();
|
||||
builders.add(client().prepareIndex("test", "type", "1").setSource("{\"theField\":\"foo\"}"));
|
||||
builders.add(client().prepareIndex("test", "type", "2").setSource("{\"theField\":\"foo 2\"}"));
|
||||
@ -370,50 +388,34 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
templateParams.put("fieldParam", "foo");
|
||||
|
||||
SearchResponse searchResponse = client()
|
||||
.prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/mustache/1a", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
templateParams)).get();
|
||||
assertHitCount(searchResponse, 4);
|
||||
|
||||
try {
|
||||
client().prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/template_index/mustache/1000", ScriptService.ScriptType.STORED,
|
||||
MustacheScriptEngineService.NAME, null, templateParams)).get();
|
||||
fail("shouldn't get here");
|
||||
} catch (SearchPhaseExecutionException spee) {
|
||||
//all good
|
||||
}
|
||||
|
||||
try {
|
||||
searchResponse = client()
|
||||
.prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/myindex/mustache/1", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
templateParams)).get();
|
||||
assertFailures(searchResponse);
|
||||
} catch (SearchPhaseExecutionException spee) {
|
||||
//all good
|
||||
}
|
||||
|
||||
searchResponse = client().prepareSearch("test").setTypes("type")
|
||||
.setTemplate(new Template("1a", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null, templateParams))
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest().indices("test").types("type"))
|
||||
.setScript("/mustache/1a")
|
||||
.setScriptType(ScriptType.STORED)
|
||||
.setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse, 4);
|
||||
assertHitCount(searchResponse.getResponse(), 4);
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest().indices("test").types("type"))
|
||||
.setScript("/template_index/mustache/1000")
|
||||
.setScriptType(ScriptType.STORED)
|
||||
.setScriptParams(templateParams)
|
||||
.get());
|
||||
|
||||
expectThrows(IllegalArgumentException.class, () -> new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest().indices("test").types("type"))
|
||||
.setScript("/myindex/mustache/1")
|
||||
.setScriptType(ScriptType.STORED)
|
||||
.setScriptParams(templateParams)
|
||||
.get());
|
||||
|
||||
templateParams.put("fieldParam", "bar");
|
||||
searchResponse = client()
|
||||
.prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/mustache/2", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
templateParams)).get();
|
||||
assertHitCount(searchResponse, 1);
|
||||
searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("/mustache/2").setScriptType(ScriptService.ScriptType.STORED).setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse.getResponse(), 1);
|
||||
|
||||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("fieldParam", "bar");
|
||||
@ -459,16 +461,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
templateParams.put("P_Keyword1", "dev");
|
||||
|
||||
try {
|
||||
client().prepareSearch("testindex")
|
||||
.setTypes("test")
|
||||
.setTemplate(
|
||||
new Template("git01", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
templateParams)).get();
|
||||
fail("Broken test template is parsing w/o error.");
|
||||
} catch (SearchPhaseExecutionException e) {
|
||||
// the above is expected to fail
|
||||
}
|
||||
ParsingException e = expectThrows(ParsingException.class, () -> new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("testindex").types("test"))
|
||||
.setScript("git01").setScriptType(ScriptService.ScriptType.STORED).setScriptParams(templateParams)
|
||||
.get());
|
||||
assertThat(e.getMessage(), containsString("[match] query does not support type ooophrase_prefix"));
|
||||
|
||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||
.setScriptLang(MustacheScriptEngineService.NAME)
|
||||
@ -476,13 +473,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
.setSource(new BytesArray("{\"query\": {\"match\": {\"searchtext\": {\"query\": \"{{P_Keyword1}}\"," +
|
||||
"\"type\": \"phrase_prefix\"}}}}")));
|
||||
|
||||
SearchResponse searchResponse = client()
|
||||
.prepareSearch("testindex")
|
||||
.setTypes("test")
|
||||
.setTemplate(
|
||||
new Template("git01", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null, templateParams))
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("testindex").types("test"))
|
||||
.setScript("git01").setScriptType(ScriptService.ScriptType.STORED).setScriptParams(templateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse, 1);
|
||||
assertHitCount(searchResponse.getResponse(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,13 +503,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
||||
String[] fieldParams = {"foo","bar"};
|
||||
arrayTemplateParams.put("fieldParam", fieldParams);
|
||||
|
||||
SearchResponse searchResponse = client()
|
||||
.prepareSearch("test")
|
||||
.setTypes("type")
|
||||
.setTemplate(
|
||||
new Template("/mustache/4", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
arrayTemplateParams)).get();
|
||||
assertHitCount(searchResponse, 5);
|
||||
SearchTemplateResponse searchResponse = new SearchTemplateRequestBuilder(client())
|
||||
.setRequest(new SearchRequest("test").types("type"))
|
||||
.setScript("/mustache/4").setScriptType(ScriptService.ScriptType.STORED).setScriptParams(arrayTemplateParams)
|
||||
.get();
|
||||
assertHitCount(searchResponse.getResponse(), 5);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
{"index":["test0", "test1"], "request_cache": true}
|
||||
{"inline": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } }
|
||||
{"index" : "test2,test3", "type" : "type1", "preference": "_local"}
|
||||
{"inline": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } }
|
||||
{"index" : ["test4", "test1"], "type" : [ "type2", "type1" ], "routing": "123"}
|
||||
{"inline": {"query" : {"match_{{template}}" :{}}}, "params": {"template": "all" } }
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"query": {
|
||||
"match": {
|
||||
"{{field}}": {
|
||||
"query" : "{{value}}",
|
||||
"operator" : "{{operator}}{{^operator}}or{{/operator}}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"size": {{size}}
|
||||
}
|
@ -18,12 +18,21 @@
|
||||
|
||||
- do:
|
||||
search_template:
|
||||
body: { "template" : { "query": { "term": { "text": { "value": "{{template}}" } } } }, "params": { "template": "value1" } }
|
||||
body: { "inline" : { "query": { "term": { "text": { "value": "{{template}}" } } } }, "params": { "template": "value1" } }
|
||||
|
||||
- match: { hits.total: 1 }
|
||||
|
||||
- do:
|
||||
search_template:
|
||||
body: { "template" : { "query": { "match_{{template}}": {} } }, "params" : { "template" : "all" } }
|
||||
body: { "inline" : { "query": { "match_{{template}}": {} } }, "params" : { "template" : "all" } }
|
||||
|
||||
- match: { hits.total: 2 }
|
||||
|
||||
---
|
||||
"Missing template search request":
|
||||
|
||||
- do:
|
||||
catch: missing
|
||||
search_template:
|
||||
body: { "id" : "unknown", "params": { "template": "value1" } }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
"Basic multi-search":
|
||||
"Basic multi-search with template query":
|
||||
- do:
|
||||
index:
|
||||
index: test_1
|
||||
@ -24,26 +24,6 @@
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
- do:
|
||||
msearch:
|
||||
body:
|
||||
- index: test_1
|
||||
- query:
|
||||
match_all: {}
|
||||
- index: test_2
|
||||
- query:
|
||||
match_all: {}
|
||||
- search_type: query_then_fetch
|
||||
index: test_1
|
||||
- query:
|
||||
match: {foo: bar}
|
||||
|
||||
- match: { responses.0.hits.total: 3 }
|
||||
- match: { responses.1.error.root_cause.0.type: index_not_found_exception }
|
||||
- match: { responses.1.error.root_cause.0.reason: "/no.such.index/" }
|
||||
- match: { responses.1.error.root_cause.0.index: test_2 }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
|
||||
- do:
|
||||
msearch:
|
||||
body:
|
||||
|
@ -0,0 +1,126 @@
|
||||
---
|
||||
setup:
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: bar }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 2
|
||||
body: { foo: baz }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 3
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_2
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
---
|
||||
"Basic multi-search template":
|
||||
|
||||
- do:
|
||||
template.msearch:
|
||||
body:
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {"foo": "{{value}}"} } }'
|
||||
params:
|
||||
value: "foo"
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {"{{field}}": "{{value}}"} } }'
|
||||
params:
|
||||
field: "foo"
|
||||
value: "bar"
|
||||
- index: _all
|
||||
- inline: '{"query": {"{{query_type}}": {{query_content}} } }'
|
||||
params:
|
||||
query_type: "match_all"
|
||||
query_content: "{}"
|
||||
- index: _all
|
||||
- inline:
|
||||
query:
|
||||
match: {foo: "{{text}}"}
|
||||
size: 0
|
||||
params:
|
||||
text: "baz"
|
||||
|
||||
- match: { responses.0.hits.total: 2 }
|
||||
- match: { responses.1.hits.total: 1 }
|
||||
- match: { responses.2.hits.total: 4 }
|
||||
- match: { responses.3.hits.total: 1 }
|
||||
- length: { responses.3.hits.hits: 0 }
|
||||
|
||||
|
||||
---
|
||||
"Multi-search template with errors":
|
||||
|
||||
- do:
|
||||
template.msearch:
|
||||
body:
|
||||
# Search 0 is OK
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {"foo": "{{value}}"} } }'
|
||||
params:
|
||||
value: "foo"
|
||||
# Search 1 has an unclosed JSON template
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {'
|
||||
params:
|
||||
field: "foo"
|
||||
value: "bar"
|
||||
# Search 2 is OK
|
||||
- index: _all
|
||||
- inline:
|
||||
query:
|
||||
match: {foo: "{{text}}"}
|
||||
params:
|
||||
text: "baz"
|
||||
# Search 3 has an unknown query type
|
||||
- index: index_*
|
||||
- inline: '{"query": {"{{query_type}}": {} }' # Unknown query type
|
||||
params:
|
||||
query_type: "unknown"
|
||||
|
||||
- match: { responses.0.hits.total: 2 }
|
||||
- match: { responses.1.error.root_cause.0.type: json_parse_exception }
|
||||
- match: { responses.1.error.root_cause.0.reason: "/Unexpected.end.of.input/" }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
- match: { responses.3.error.root_cause.0.type: parsing_exception }
|
||||
- match: { responses.3.error.root_cause.0.reason: "/no.\\[query\\].registered.for.\\[unknown\\]/" }
|
||||
|
||||
---
|
||||
"Multi-search template with invalid request":
|
||||
|
||||
- do:
|
||||
catch: /(.)*action_request_validation_exception(.)*template.is.missing(.)*/
|
||||
template.msearch:
|
||||
body:
|
||||
# Search 0 is OK
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {"foo": "{{value}}"} } }'
|
||||
params:
|
||||
value: "foo"
|
||||
# Search 1 has not template
|
||||
- index: _all
|
||||
- inline: ""
|
||||
# Search 2 is OK
|
||||
- index: index_*
|
||||
- inline: '{"query": {"match": {"foo": "{{value}}"} } }'
|
||||
params:
|
||||
value: "bar"
|
@ -0,0 +1,66 @@
|
||||
---
|
||||
setup:
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: bar }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 2
|
||||
body: { foo: baz }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 3
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_2
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
---
|
||||
"Basic multi-search using stored template":
|
||||
|
||||
- do:
|
||||
put_template:
|
||||
id: stored_template_1
|
||||
body: {"template": {"query": {"match": {"{{field}}": "{{value}}" }}}}
|
||||
- match: { acknowledged: true }
|
||||
|
||||
- do:
|
||||
template.msearch:
|
||||
body:
|
||||
- index: index_*
|
||||
- id: stored_template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "foo"
|
||||
- index: _all
|
||||
- id: stored_template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "bar"
|
||||
- index: index_2
|
||||
- id: stored_template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "foo"
|
||||
|
||||
- match: { responses.0.hits.total: 2 }
|
||||
- match: { responses.1.hits.total: 1 }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
|
@ -0,0 +1,72 @@
|
||||
---
|
||||
setup:
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: bar }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 2
|
||||
body: { foo: baz }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 3
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_2
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
---
|
||||
"Basic multi-search using file template":
|
||||
|
||||
- do:
|
||||
render_search_template:
|
||||
body: { "file": "template_1", "params": { "field": "foo", "value": "bar", "size": 20 } }
|
||||
|
||||
- match: { template_output.query.match.foo.query: "bar" }
|
||||
- match: { template_output.query.match.foo.operator: "or" }
|
||||
- match: { template_output.size: 20 }
|
||||
|
||||
- do:
|
||||
template.msearch:
|
||||
body:
|
||||
- index: index_*
|
||||
- file: template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "foo"
|
||||
size: 10
|
||||
- index: _all
|
||||
- file: template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "bar"
|
||||
operator: "and"
|
||||
size: 50
|
||||
- index: index_2
|
||||
- file: template_1
|
||||
params:
|
||||
field: "foo"
|
||||
value: "foo"
|
||||
size: 0
|
||||
|
||||
- match: { responses.0.hits.total: 2 }
|
||||
- match: { responses.1.hits.total: 1 }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"template.msearch": {
|
||||
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html",
|
||||
"methods": ["GET", "POST"],
|
||||
"url": {
|
||||
"path": "/_msearch/template",
|
||||
"paths": ["/_msearch/template", "/{index}/_msearch/template", "/{index}/{type}/_msearch/template"],
|
||||
"parts": {
|
||||
"index": {
|
||||
"type" : "list",
|
||||
"description" : "A comma-separated list of index names to use as default"
|
||||
},
|
||||
"type": {
|
||||
"type" : "list",
|
||||
"description" : "A comma-separated list of document types to use as default"
|
||||
}
|
||||
},
|
||||
"params": {
|
||||
"search_type": {
|
||||
"type" : "enum",
|
||||
"options" : ["query_then_fetch", "query_and_fetch", "dfs_query_then_fetch", "dfs_query_and_fetch"],
|
||||
"description" : "Search operation type"
|
||||
}
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"description": "The request definitions (metadata-search request definition pairs), separated by newlines",
|
||||
"required" : true,
|
||||
"serialize" : "bulk"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
{
|
||||
"template.search": {
|
||||
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html",
|
||||
"methods": ["GET", "POST"],
|
||||
"url": {
|
||||
"path": "/_search/template",
|
||||
"paths": ["/_search/template", "/{index}/_search/template", "/{index}/{type}/_search/template"],
|
||||
"parts": {
|
||||
"index": {
|
||||
"type" : "list",
|
||||
"description" : "A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices"
|
||||
},
|
||||
"type": {
|
||||
"type" : "list",
|
||||
"description" : "A comma-separated list of document types to search; leave empty to perform the operation on all types"
|
||||
}
|
||||
},
|
||||
"params" : {
|
||||
"ignore_unavailable": {
|
||||
"type" : "boolean",
|
||||
"description" : "Whether specified concrete indices should be ignored when unavailable (missing or closed)"
|
||||
},
|
||||
"allow_no_indices": {
|
||||
"type" : "boolean",
|
||||
"description" : "Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)"
|
||||
},
|
||||
"expand_wildcards": {
|
||||
"type" : "enum",
|
||||
"options" : ["open","closed","none","all"],
|
||||
"default" : "open",
|
||||
"description" : "Whether to expand wildcard expression to concrete indices that are open, closed or both."
|
||||
},
|
||||
"preference": {
|
||||
"type" : "string",
|
||||
"description" : "Specify the node or shard the operation should be performed on (default: random)"
|
||||
},
|
||||
"routing": {
|
||||
"type" : "list",
|
||||
"description" : "A comma-separated list of specific routing values"
|
||||
},
|
||||
"scroll": {
|
||||
"type" : "duration",
|
||||
"description" : "Specify how long a consistent view of the index should be maintained for scrolled search"
|
||||
},
|
||||
"search_type": {
|
||||
"type" : "enum",
|
||||
"options" : ["query_then_fetch", "query_and_fetch", "dfs_query_then_fetch", "dfs_query_and_fetch"],
|
||||
"description" : "Search operation type"
|
||||
}
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"description": "The search definition template and its params"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
---
|
||||
setup:
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: bar }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 2
|
||||
body: { foo: baz }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_1
|
||||
type: test
|
||||
id: 3
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
index:
|
||||
index: index_2
|
||||
type: test
|
||||
id: 1
|
||||
body: { foo: foo }
|
||||
|
||||
- do:
|
||||
indices.refresh: {}
|
||||
|
||||
---
|
||||
"Basic multi-search":
|
||||
|
||||
- do:
|
||||
msearch:
|
||||
body:
|
||||
- index: index_*
|
||||
- query:
|
||||
match: {foo: foo}
|
||||
- index: index_2
|
||||
- query:
|
||||
match_all: {}
|
||||
- index: index_1
|
||||
- query:
|
||||
match: {foo: foo}
|
||||
- index: index_3
|
||||
- query:
|
||||
match_all: {}
|
||||
- type: test
|
||||
- query:
|
||||
match_all: {}
|
||||
|
||||
- match: { responses.0.hits.total: 2 }
|
||||
- match: { responses.1.hits.total: 1 }
|
||||
- match: { responses.2.hits.total: 1 }
|
||||
- match: { responses.3.error.root_cause.0.type: index_not_found_exception }
|
||||
- match: { responses.3.error.root_cause.0.reason: "/no.such.index/" }
|
||||
- match: { responses.3.error.root_cause.0.index: index_3 }
|
||||
- match: { responses.4.hits.total: 4 }
|
||||
|
@ -28,8 +28,10 @@ import org.elasticsearch.indices.IndicesService;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.dfs.DfsPhase;
|
||||
import org.elasticsearch.search.fetch.FetchPhase;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.search.query.QueryPhase;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
|
||||
@ -74,9 +76,8 @@ public class MockSearchService extends SearchService {
|
||||
@Inject
|
||||
public MockSearchService(Settings settings, ClusterSettings clusterSettings, ClusterService clusterService,
|
||||
IndicesService indicesService, ThreadPool threadPool, ScriptService scriptService,
|
||||
BigArrays bigArrays, FetchPhase fetchPhase, AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
super(settings, clusterSettings, clusterService, indicesService, threadPool, scriptService, bigArrays,
|
||||
fetchPhase, aggParsers, suggesters);
|
||||
BigArrays bigArrays, FetchPhase fetchPhase) {
|
||||
super(settings, clusterSettings, clusterService, indicesService, threadPool, scriptService, bigArrays, fetchPhase);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user