Indexed Scripts/Templates: Add support for storing/deleting/getting scripts/template from an index.

This change allow elasticsearch users to store scripts and templates in an index for use at search time.
Scripts/Templates are stored in the .scripts index. The type of the events is set to the script language.
Templates use the mustache language so their type is be "mustache".
Adds the concept of a script type to calls to the ScriptService types are INDEXED,INLINE,FILE.
If a script type of INDEXED is supplied the script will be attempted to be loaded from the indexed, FILE will
look in the file cache and INLINE will treat the supplied script argument as the literal script.
REST endpoints are provided to do CRUD operations as is a java client library.
All query dsl points have been upgraded to allow passing in of explicit script ids and script file names.
Backwards compatible behavior has been preserved so this shouldn't break any existing querys that expect to
pass in a filename as the script/template name. The ScriptService will check the disk cache before parsing the
script.

Closes #5921 #5637 #5484
This commit is contained in:
Brian Murphy 2014-07-14 14:37:55 +01:00
parent dcb2107a1d
commit e79b7086de
90 changed files with 4394 additions and 212 deletions

View File

@ -0,0 +1,26 @@
{
"indexed_script.create": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["PUT", "POST"],
"url": {
"path": "/_search/script/{lang}/{id}",
"paths": [ "/_search/script/{lang}/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Script ID",
"required" : true
},
"lang" : {
"type" : "string",
"description" : "Script language",
"required" : true
}
}
},
"body": {
"description" : "The document",
"required" : true
}
}
}

View File

@ -0,0 +1,23 @@
{
"indexed_script.delete": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["DELETE"],
"url": {
"path": "/_search/script/{lang}/{id}",
"paths": [ "/_search/script/{lang}/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Script ID",
"required" : true
},
"lang" : {
"type" : "string",
"description" : "Script language",
"required" : true
}
}
},
"body": null
}
}

View File

@ -0,0 +1,23 @@
{
"indexed_script.get": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["GET"],
"url": {
"path": "/_search/script/{lang}/{id}",
"paths": [ "/_search/script/{lang}/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Script ID",
"required" : true
},
"lang" : {
"type" : "string",
"description" : "Script language",
"required" : true
}
}
},
"body": null
}
}

View File

@ -0,0 +1,21 @@
{
"indexed_template.create": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["PUT", "POST"],
"url": {
"path": "/_search/template/{id}",
"paths": [ "/_search/template/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Template ID",
"required" : true
}
}
},
"body": {
"description" : "The document",
"required" : true
}
}
}

View File

@ -0,0 +1,17 @@
{
"indexed_template.delete": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["DELETE"],
"url": {
"path": "/_search/template/{id}",
"paths": [ "/_search/template/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Template ID"
}
}
},
"body": null
}
}

View File

@ -0,0 +1,21 @@
{
"indexed_template.get": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/indexed-scripts.html",
"methods": ["GET"],
"url": {
"path": "/_search/template/{id}",
"paths": [ "/_search/template/{id}" ],
"parts": {
"id": {
"type" : "string",
"description" : "Template ID",
"required" : true
}
}
},
"body": {
"description" : "The document",
"required" : false
}
}
}

View File

@ -0,0 +1,41 @@
---
"Indexed script":
- do:
indexed_script.create:
id: "1"
lang: "groovy"
body: { "script": "_score * doc[\"myParent.weight\"].value" }
- match: { _id: "1" }
- do:
indexed_script.get:
id: "1"
lang: "groovy"
- match: { "script": "_score * doc[\"myParent.weight\"].value" }
- do:
indexed_script.delete:
id: "1"
lang: "groovy"
- match: { found: true }
- match: { _index: ".scripts" }
- match: { _id: "1" }
- do:
catch: request
indexed_script.create:
id: "1"
lang: "groovy"
body: { "script": "_score * foo bar + doc[\"myParent.weight\"].value" }
- match: { "error": /ElasticsearchIllegalArgumentException\SUnable\sto\sparse.*/ }
- do:
catch: request
indexed_script.create:
id: "1"
lang: "foobar"
body: { "script" : "_score * doc[\"myParent.weight\"].value" }
- match: { "error": /ElasticsearchIllegalArgumentException\Sscript_lang\snot\ssupported/ }

View File

@ -0,0 +1,28 @@
---
"Indexed template":
- do:
indexed_template.create:
id: "1"
body: { "template": { "query": { "match_all": {}}, "size": "{{my_size}}" } }
- match: { _id: "1" }
- do:
indexed_template.get:
id: 1
- match: { template: "{\"query\":{\"match_all\":{}},\"size\":\"{{my_size}}\"}"}
- do:
indexed_template.delete:
id: "1"
- match: { found: true }
- match: { _index: ".scripts" }
- match: { _id: "1" }
- do:
catch: request
indexed_template.create:
id: "1"
body: { "template": { "query": { "match{{}}_all": {}}, "size": "{{my_size}}" } }
- match: { "error": /ElasticsearchIllegalArgumentException\SUnable\sto\sparse.*/ }

View File

@ -0,0 +1,38 @@
---
"Indexed Template query tests":
- do:
index:
index: test
type: testtype
id: 1
body: { "text": "value1_foo" }
- do:
index:
index: test
type: testtype
id: 2
body: { "text": "value2_foo value3_foo" }
- do:
indices.refresh: {}
- do:
indexed_template.create:
id: "1"
body: { "template": { "query": { "match" : { "text": "{{my_value}}" } }, "size": "{{my_size}}" } }
- match: { _id: "1" }
- do:
indices.refresh: {}
- do:
search_template:
body: { "template": { "id" : "1" }, "params" : { "my_value" : "value1_foo", "my_size" : 1 } }
- match: { hits.total: 1 }
- do:
search_template:
body: { "id" : "1", "params" : { "my_value" : "value1_foo", "my_size" : 1 } }
- match: { hits.total: 1 }

View File

@ -136,6 +136,12 @@ import org.elasticsearch.action.explain.TransportExplainAction;
import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.IndexAction;
import org.elasticsearch.action.index.TransportIndexAction;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.delete.TransportDeleteIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.get.TransportGetIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.put.TransportPutIndexedScriptAction;
import org.elasticsearch.action.mlt.MoreLikeThisAction;
import org.elasticsearch.action.mlt.TransportMoreLikeThisAction;
import org.elasticsearch.action.percolate.*;
@ -286,6 +292,11 @@ public class ActionModule extends AbstractModule {
registerAction(AbortBenchmarkAction.INSTANCE, TransportAbortBenchmarkAction.class);
registerAction(BenchmarkStatusAction.INSTANCE, TransportBenchmarkStatusAction.class);
//Indexed scripts
registerAction(PutIndexedScriptAction.INSTANCE, TransportPutIndexedScriptAction.class);
registerAction(GetIndexedScriptAction.INSTANCE, TransportGetIndexedScriptAction.class);
registerAction(DeleteIndexedScriptAction.INSTANCE, TransportDeleteIndexedScriptAction.class);
// register Name -> GenericAction Map that can be injected to instances.
MapBinder<String, GenericAction> actionsBinder
= MapBinder.newMapBinder(binder(), String.class, GenericAction.class);

View File

@ -46,7 +46,7 @@ public class GetResponse extends ActionResponse implements Iterable<GetField>, T
GetResponse() {
}
GetResponse(GetResult getResult) {
public GetResponse(GetResult getResult) {
this.getResult = getResult;
}
@ -151,6 +151,12 @@ public class GetResponse extends ActionResponse implements Iterable<GetField>, T
return getResult.toXContent(builder, params);
}
public static GetResponse readGetResponse(StreamInput in) throws IOException {
GetResponse result = new GetResponse();
result.readFrom(in);
return result;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);

View File

@ -110,6 +110,19 @@ public class IndexRequest extends ShardReplicationOperationRequest<IndexRequest>
throw new ElasticsearchIllegalArgumentException("No type match for [" + id + "]");
}
}
public static OpType fromString(String sOpType) throws ElasticsearchIllegalArgumentException {
String lowersOpType = sOpType.toLowerCase(Locale.ROOT);
switch(lowersOpType){
case "create":
return OpType.CREATE;
case "index":
return OpType.INDEX;
default:
throw new ElasticsearchIllegalArgumentException("opType [" + sOpType + "] not allowed, either [index] or [create] are allowed");
}
}
}
private String type;
@ -469,20 +482,6 @@ public class IndexRequest extends ShardReplicationOperationRequest<IndexRequest>
return this;
}
/**
* Sets a string representation of the {@link #opType(org.elasticsearch.action.index.IndexRequest.OpType)}. Can
* be either "index" or "create".
*/
public IndexRequest opType(String opType) throws ElasticsearchIllegalArgumentException {
if ("create".equals(opType)) {
return opType(OpType.CREATE);
} else if ("index".equals(opType)) {
return opType(OpType.INDEX);
} else {
throw new ElasticsearchIllegalArgumentException("No index opType matching [" + opType + "]");
}
}
/**
* Set to <tt>true</tt> to force this index to use {@link OpType#CREATE}.
*/

View File

@ -231,7 +231,7 @@ public class IndexRequestBuilder extends ShardReplicationOperationRequestBuilder
* be either "index" or "create".
*/
public IndexRequestBuilder setOpType(String opType) {
request.opType(opType);
request.opType(IndexRequest.OpType.fromString(opType));
return this;
}

View File

@ -0,0 +1,45 @@
/*
* 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.indexedscripts.delete;
import org.elasticsearch.action.ClientAction;
import org.elasticsearch.client.Client;
/**
*/
public class DeleteIndexedScriptAction extends ClientAction<DeleteIndexedScriptRequest, DeleteIndexedScriptResponse, DeleteIndexedScriptRequestBuilder> {
public static final DeleteIndexedScriptAction INSTANCE = new DeleteIndexedScriptAction();
public static final String NAME = "deleteIndexedScript";
private DeleteIndexedScriptAction() {
super(NAME);
}
@Override
public DeleteIndexedScriptResponse newResponse() {
return new DeleteIndexedScriptResponse();
}
@Override
public DeleteIndexedScriptRequestBuilder newRequestBuilder(Client client) {
return new DeleteIndexedScriptRequestBuilder(client);
}
}

View File

@ -0,0 +1,164 @@
/*
* 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.indexedscripts.delete;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import static org.elasticsearch.action.ValidateActions.addValidationError;
/**
* A request to delete a script from the script index based on its scriptLang and id. Best created using
* <p/>
* <p>The operation requires the , {@link #scriptLang(String)} and {@link #id(String)} to
* be set.
*
* @see DeleteIndexedScriptResponse
* @see org.elasticsearch.client.Client#deleteIndexedScript(DeleteIndexedScriptRequest)
*/
public class DeleteIndexedScriptRequest extends ActionRequest<DeleteIndexedScriptRequest> {
private String scriptLang;
private String id;
@Nullable
private long version = Versions.MATCH_ANY;
private VersionType versionType = VersionType.INTERNAL;
/**
* Constructs a new delete request against the specified index with the scriptLang and id.
*
* @param scriptLang The scriptLang of the document
* @param id The id of the document
*/
public DeleteIndexedScriptRequest(String scriptLang, String id) {
this.scriptLang = scriptLang;
this.id = id;
}
public DeleteIndexedScriptRequest(DeleteIndexedScriptRequest request) {
super(request);
this.scriptLang = request.scriptLang();
this.id = request.id();
this.version = request.version();
this.versionType = request.versionType();
}
public DeleteIndexedScriptRequest() {
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (scriptLang == null) {
validationException = addValidationError("scriptLang is missing", validationException);
}
if (id == null) {
validationException = addValidationError("id is missing", validationException);
}
if (!versionType.validateVersionForWrites(version)) {
validationException = addValidationError("illegal version value [" + version + "] for version scriptLang [" + versionType.name() + "]", validationException);
}
return validationException;
}
/**
* The scriptLang of the document to delete.
*/
public String scriptLang() {
return scriptLang;
}
/**
* Sets the scriptLang of the document to delete.
*/
public DeleteIndexedScriptRequest scriptLang(String type) {
this.scriptLang = type;
return this;
}
/**
* The id of the document to delete.
*/
public String id() {
return id;
}
/**
* Sets the id of the document to delete.
*/
public DeleteIndexedScriptRequest id(String id) {
this.id = id;
return this;
}
/**
* Sets the version, which will cause the delete operation to only be performed if a matching
* version exists and no changes happened on the doc since then.
*/
public DeleteIndexedScriptRequest version(long version) {
this.version = version;
return this;
}
public long version() {
return this.version;
}
public DeleteIndexedScriptRequest versionType(VersionType versionType) {
this.versionType = versionType;
return this;
}
public VersionType versionType() {
return this.versionType;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
scriptLang = in.readString();
id = in.readString();
version = Versions.readVersion(in);
versionType = VersionType.fromValue(in.readByte());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(scriptLang);
out.writeString(id);
Versions.writeVersion(version, out);
out.writeByte(versionType.getValue());
}
@Override
public String toString() {
return "delete {[" + ScriptService.SCRIPT_INDEX + "][" + scriptLang + "][" + id + "]}";
}
}

View File

@ -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.indexedscripts.delete;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.VersionType;
/**
* A delete document action request builder.
*/
public class DeleteIndexedScriptRequestBuilder extends ActionRequestBuilder<DeleteIndexedScriptRequest, DeleteIndexedScriptResponse, DeleteIndexedScriptRequestBuilder, Client> {
public DeleteIndexedScriptRequestBuilder(Client client) {
super(client, new DeleteIndexedScriptRequest());
}
/**
* Sets the language of the script to delete.
*/
public DeleteIndexedScriptRequestBuilder setScriptLang(String scriptLang) {
request.scriptLang(scriptLang);
return this;
}
/**
* Sets the id of the document to delete.
*/
public DeleteIndexedScriptRequestBuilder setId(String id) {
request.id(id);
return this;
}
/**
* Sets the type of versioning to use. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}.
*/
public DeleteIndexedScriptRequestBuilder setVersionType(VersionType versionType) {
request.versionType(versionType);
return this;
}
@Override
protected void doExecute(final ActionListener<DeleteIndexedScriptResponse> listener) {
client.deleteIndexedScript(request, listener);
}
}

View File

@ -0,0 +1,108 @@
/*
* 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.indexedscripts.delete;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
/**
* The response of the delete action.
*
* @see DeleteIndexedScriptRequest
* @see org.elasticsearch.client.Client#delete(DeleteIndexedScriptRequest)
*/
public class DeleteIndexedScriptResponse extends ActionResponse {
private String index;
private String id;
private String type;
private long version;
private boolean found;
public DeleteIndexedScriptResponse() {
}
public DeleteIndexedScriptResponse(String index, String type, String id, long version, boolean found) {
this.index = index;
this.id = id;
this.type = type;
this.version = version;
this.found = found;
}
/**
* The index the document was deleted from.
*/
public String getIndex() {
return this.index;
}
/**
* The type of the document deleted.
*/
public String getType() {
return this.type;
}
/**
* The id of the document deleted.
*/
public String getId() {
return this.id;
}
/**
* The version of the delete operation.
*/
public long getVersion() {
return this.version;
}
/**
* Returns <tt>true</tt> if a doc was found to delete.
*/
public boolean isFound() {
return found;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
index = in.readString();
type = in.readString();
id = in.readString();
version = in.readLong();
found = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(index);
out.writeString(type);
out.writeString(id);
out.writeLong(version);
out.writeBoolean(found);
}
}

View File

@ -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.indexedscripts.delete;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.delete.DeleteAction;
import org.elasticsearch.action.support.DelegatingActionListener;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.*;
/**
* Performs the delete operation.
*/
public class TransportDeleteIndexedScriptAction extends HandledTransportAction<DeleteIndexedScriptRequest, DeleteIndexedScriptResponse> {
private ScriptService scriptService;
private Client client;
@Inject
public TransportDeleteIndexedScriptAction(Settings settings, ThreadPool threadPool, ScriptService scriptService,
Client client, TransportService transportService) {
super(settings, threadPool, transportService, DeleteIndexedScriptAction.NAME);
this.scriptService = scriptService;
this.client = client;
}
@Override
public DeleteIndexedScriptRequest newRequestInstance(){
return new DeleteIndexedScriptRequest();
}
@Override
protected void doExecute(final DeleteIndexedScriptRequest request, final ActionListener<DeleteIndexedScriptResponse> listener) {
scriptService.deleteScriptFromIndex(client, request.scriptLang(), request.id(), request.version(), new DelegatingActionListener<DeleteResponse, DeleteIndexedScriptResponse>(listener) {
@Override
public DeleteIndexedScriptResponse getDelegatedFromInstigator(DeleteResponse deleteResponse){
return new DeleteIndexedScriptResponse(deleteResponse.getIndex(),deleteResponse.getType(),deleteResponse.getType(),deleteResponse.getVersion(), deleteResponse.isFound());
}
});
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.
*/
/**
* Delete action.
*/
package org.elasticsearch.action.indexedscripts.delete;

View File

@ -0,0 +1,46 @@
/*
* 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.indexedscripts.get;
import org.elasticsearch.action.ClientAction;
import org.elasticsearch.client.Client;
/**
*/
public class GetIndexedScriptAction extends ClientAction<GetIndexedScriptRequest, GetIndexedScriptResponse, GetIndexedScriptRequestBuilder> {
public static final GetIndexedScriptAction INSTANCE = new GetIndexedScriptAction();
public static final String NAME = "getIndexedScript";
private GetIndexedScriptAction() {
super(NAME);
}
@Override
public GetIndexedScriptResponse newResponse() {
return new GetIndexedScriptResponse();
}
@Override
public GetIndexedScriptRequestBuilder newRequestBuilder(Client client) {
return new GetIndexedScriptRequestBuilder(client);
}
}

View File

@ -0,0 +1,252 @@
/*
* 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.indexedscripts.get;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ValidateActions;
import org.elasticsearch.action.support.single.shard.SingleShardOperationRequest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.fetch.source.FetchSourceContext;
import java.io.IOException;
/**
* A request to get a document (its source) from an index based on its type/language (optional) and id. Best created using
* {@link org.elasticsearch.client.Requests#getRequest(String)}.
* <p/>
* <p>The operation requires the {@link #index()}, {@link #scriptLang(String)} and {@link #id(String)}
* to be set.
*
* @see GetIndexedScriptResponse
*/
public class GetIndexedScriptRequest extends SingleShardOperationRequest<GetIndexedScriptRequest> {
protected String scriptLang;
protected String id;
protected String preference;
protected String routing;
private FetchSourceContext fetchSourceContext;
private boolean refresh = false;
Boolean realtime;
private VersionType versionType = VersionType.INTERNAL;
private long version = Versions.MATCH_ANY;
/**
* Constructs a new get request against the script index. The {@link #scriptLang(String)} and {@link #id(String)}
* must be set.
*/
public GetIndexedScriptRequest() {
super(ScriptService.SCRIPT_INDEX);
}
/**
* Constructs a new get request against the script index with the type and id.
*
* @param index The index to get the document from
* @param scriptLang The type of the document
* @param id The id of the document
*/
public GetIndexedScriptRequest(String index, String scriptLang, String id) {
super(index);
this.scriptLang = scriptLang;
this.id = id;
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = super.validate();
if (scriptLang == null) {
validationException = ValidateActions.addValidationError("type is missing", validationException);
}
if (id == null) {
validationException = ValidateActions.addValidationError("id is missing", validationException);
}
if (!versionType.validateVersionForReads(version)) {
validationException = ValidateActions.addValidationError("illegal version value [" + version + "] for version type [" + versionType.name() + "]",
validationException);
}
return validationException;
}
/**
* Sets the type of the document to fetch.
*/
public GetIndexedScriptRequest scriptLang(@Nullable String type) {
this.scriptLang = type;
return this;
}
/**
* Sets the id of the document to fetch.
*/
public GetIndexedScriptRequest id(String id) {
this.id = id;
return this;
}
/**
* Controls the shard routing of the request. Using this value to hash the shard
* and not the id.
*/
public GetIndexedScriptRequest routing(String routing) {
this.routing = routing;
return this;
}
/**
* Explicitly specify the fields that will be returned. By default, the <tt>_source</tt>
* field will be returned.
*/
public String[] fields() {
return null;
}
/**
* Sets the preference to execute the search. Defaults to randomize across shards. Can be set to
* <tt>_local</tt> to prefer local shards, <tt>_primary</tt> to execute only on primary shards, or
* a custom value, which guarantees that the same order will be used across different requests.
*/
public GetIndexedScriptRequest preference(String preference) {
this.preference = preference;
return this;
}
public String scriptLang() {
return scriptLang;
}
public String id() {
return id;
}
public String routing() {
return routing;
}
public String preference() {
return this.preference;
}
/**
* Should a refresh be executed before this get operation causing the operation to
* return the latest value. Note, heavy get should not set this to <tt>true</tt>. Defaults
* to <tt>false</tt>.
*/
public GetIndexedScriptRequest refresh(boolean refresh) {
this.refresh = refresh;
return this;
}
public boolean refresh() {
return this.refresh;
}
public boolean realtime() {
return this.realtime == null ? true : this.realtime;
}
public GetIndexedScriptRequest realtime(Boolean realtime) {
this.realtime = realtime;
return this;
}
/**
* Sets the version, which will cause the get operation to only be performed if a matching
* version exists and no changes happened on the doc since then.
*/
public long version() {
return version;
}
public GetIndexedScriptRequest version(long version) {
this.version = version;
return this;
}
/**
* Sets the versioning type. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}.
*/
public GetIndexedScriptRequest versionType(VersionType versionType) {
this.versionType = versionType;
return this;
}
public VersionType versionType() {
return this.versionType;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
scriptLang = in.readString();
id = in.readString();
preference = in.readOptionalString();
refresh = in.readBoolean();
byte realtime = in.readByte();
if (realtime == 0) {
this.realtime = false;
} else if (realtime == 1) {
this.realtime = true;
}
this.versionType = VersionType.fromValue(in.readByte());
this.version = Versions.readVersionWithVLongForBW(in);
fetchSourceContext = FetchSourceContext.optionalReadFromStream(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(scriptLang);
out.writeString(id);
out.writeOptionalString(preference);
out.writeBoolean(refresh);
if (realtime == null) {
out.writeByte((byte) -1);
} else if (realtime == false) {
out.writeByte((byte) 0);
} else {
out.writeByte((byte) 1);
}
out.writeByte(versionType.getValue());
Versions.writeVersionWithVLongForBW(version, out);
FetchSourceContext.optionalWriteToStream(fetchSourceContext, out);
}
@Override
public String toString() {
return "[" + index + "][" + scriptLang + "][" + id + "]: routing [" + routing + "]";
}
}

View File

@ -0,0 +1,102 @@
/*
* 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.indexedscripts.get;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.VersionType;
/**
* A get document action request builder.
*/
public class GetIndexedScriptRequestBuilder extends ActionRequestBuilder<GetIndexedScriptRequest, GetIndexedScriptResponse, GetIndexedScriptRequestBuilder, Client> {
public GetIndexedScriptRequestBuilder(Client client) {
super(client, new GetIndexedScriptRequest());
}
/**
* Sets the type of the document to fetch. If set to <tt>null</tt>, will use just the id to fetch the
* first document matching it.
*/
public GetIndexedScriptRequestBuilder setScriptLang(@Nullable String type) {
request.scriptLang(type);
return this;
}
/**
* Sets the id of the document to fetch.
*/
public GetIndexedScriptRequestBuilder setId(String id) {
request.id(id);
return this;
}
/**
* Sets the preference to execute the search. Defaults to randomize across shards. Can be set to
* <tt>_local</tt> to prefer local shards, <tt>_primary</tt> to execute only on primary shards, or
* a custom value, which guarantees that the same order will be used across different requests.
*/
public GetIndexedScriptRequestBuilder setPreference(String preference) {
request.preference(preference);
return this;
}
/**
* Should a refresh be executed before this get operation causing the operation to
* return the latest value. Note, heavy get should not set this to <tt>true</tt>. Defaults
* to <tt>false</tt>.
*/
public GetIndexedScriptRequestBuilder setRefresh(boolean refresh) {
request.refresh(refresh);
return this;
}
public GetIndexedScriptRequestBuilder setRealtime(Boolean realtime) {
request.realtime(realtime);
return this;
}
/**
* Sets the version, which will cause the get operation to only be performed if a matching
* version exists and no changes happened on the doc since then.
*/
public GetIndexedScriptRequestBuilder setVersion(long version) {
request.version(version);
return this;
}
/**
* Sets the versioning type. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}.
*/
public GetIndexedScriptRequestBuilder setVersionType(VersionType versionType) {
request.versionType(versionType);
return this;
}
@Override
protected void doExecute(ActionListener<GetIndexedScriptResponse> listener) {
client.getIndexedScript(request, listener);
}
}

View File

@ -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.indexedscripts.get;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.get.GetResponse;
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.XContentBuilder;
import org.elasticsearch.index.get.GetField;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
/**
* The response of a get script action.
*
* @see GetIndexedScriptRequest
*/
public class GetIndexedScriptResponse extends ActionResponse implements Iterable<GetField>, ToXContent {
private GetResponse getResponse;
GetIndexedScriptResponse() {
}
GetIndexedScriptResponse(GetResponse getResult) {
this.getResponse = getResult;
}
/**
* Does the document exists.
*/
public boolean isExists() {
return getResponse.isExists();
}
/**
* The type of the document.
*/
public String getScriptLang() {
return getResponse.getType();
}
/**
* The id of the document.
*/
public String getId() {
return getResponse.getId();
}
/**
* The version of the doc.
*/
public long getVersion() {
return getResponse.getVersion();
}
/**
* The source of the document (as a string).
*/
public String getScript() {
return ScriptService.getScriptFromResponse(getResponse);
}
@Override
public Iterator<GetField> iterator() {
return getResponse.iterator();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return getResponse.toXContent(builder, params);
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
getResponse = GetResponse.readGetResponse(in);
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
getResponse.writeTo(out);
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.indexedscripts.get;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.action.support.TransportAction;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.BaseTransportRequestHandler;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportService;
/**
* Performs the get operation.
*/
public class TransportGetIndexedScriptAction extends HandledTransportAction<GetIndexedScriptRequest, GetIndexedScriptResponse> {
public static final boolean REFRESH_FORCE = false;
ScriptService scriptService;
Client client;
@Inject
public TransportGetIndexedScriptAction(Settings settings, ThreadPool threadPool, ScriptService scriptService,
TransportService transportService, Client client) {
super(settings, threadPool,transportService, GetIndexedScriptAction.NAME);
this.scriptService = scriptService;
this.client = client;
}
@Override
public GetIndexedScriptRequest newRequestInstance(){
return new GetIndexedScriptRequest();
}
@Override
public void doExecute(GetIndexedScriptRequest request, ActionListener<GetIndexedScriptResponse> listener){
try {
GetResponse scriptResponse = scriptService.queryScriptIndex(client, request.scriptLang(), request.id(), request.version(), request.versionType());
listener.onResponse(new GetIndexedScriptResponse(scriptResponse));
} catch(Throwable e){
listener.onFailure(e);
}
}
}

View File

@ -0,0 +1,19 @@
/*
* 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.indexedscripts.get;

View File

@ -0,0 +1,48 @@
/*
* 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.indexedscripts.put;
import org.elasticsearch.action.ClientAction;
import org.elasticsearch.client.Client;
/**
*/
public class PutIndexedScriptAction extends ClientAction<PutIndexedScriptRequest, PutIndexedScriptResponse, PutIndexedScriptRequestBuilder> {
public static final PutIndexedScriptAction INSTANCE = new PutIndexedScriptAction();
public static final String NAME = "putIndexedScript";
private PutIndexedScriptAction() {
super(NAME);
}
@Override
public PutIndexedScriptResponse newResponse() {
return new PutIndexedScriptResponse();
}
@Override
public PutIndexedScriptRequestBuilder newRequestBuilder(Client client) {
return new PutIndexedScriptRequestBuilder(client);
}
}

View File

@ -0,0 +1,360 @@
/*
* 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.indexedscripts.put;
import com.google.common.base.Charsets;
import org.elasticsearch.*;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.action.ValidateActions.addValidationError;
/**
* Index request to index a script to the script index and make it available at search time.
* <p/>
* <p>The request requires the {@link #scriptLang(String)}, {@link #id(String)} and
* {@link #source(byte[])} to be set.
* <p/>
* <p>The source (content to index) can be set in its bytes form using ({@link #source()} (byte[])}),
* its string form ({@link #source(String)}) or using a {@link org.elasticsearch.common.xcontent.XContentBuilder}
* ({@link #source(org.elasticsearch.common.xcontent.XContentBuilder)}).
* <p/>
* <p>If the {@link #id(String)} is not set, it will be automatically generated.
*
* @see PutIndexedScriptResponse
*/
public class PutIndexedScriptRequest extends ActionRequest<PutIndexedScriptRequest> {
private String scriptLang;
private String id;
private BytesReference source;
private boolean sourceUnsafe;
private IndexRequest.OpType opType = IndexRequest.OpType.INDEX;
private long version = Versions.MATCH_ANY;
private VersionType versionType = VersionType.INTERNAL;
private XContentType contentType = Requests.INDEX_CONTENT_TYPE;
public PutIndexedScriptRequest() {
super();
}
/**
* Constructs a new index request against the specific index and type. The
* {@link #source(byte[])} must be set.
*/
public PutIndexedScriptRequest(String scriptLang) {
super();
this.scriptLang = scriptLang;
}
/**
* Constructs a new index request against the index, type, id and using the source.
*
* @param scriptLang The scriptLang to index into
* @param id The id of document
*/
public PutIndexedScriptRequest(String scriptLang, String id) {
super();
this.scriptLang = scriptLang;
this.id = id;
}
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (scriptLang == null) {
validationException = addValidationError("scriptType is missing", validationException);
}
if (source == null) {
validationException = addValidationError("source is missing", validationException);
}
if (id == null) {
validationException = addValidationError("id is missing", validationException);
}
if (!versionType.validateVersionForWrites(version)) {
validationException = addValidationError("illegal version value [" + version + "] for version type [" + versionType.name() + "]", validationException);
}
return validationException;
}
/**
* Sets the content type that will be used when generating a document from user provided objects (like Map).
*/
public PutIndexedScriptRequest contentType(XContentType contentType) {
this.contentType = contentType;
return this;
}
/**
* The type of the indexed document.
*/
public String scriptLang() {
return scriptLang;
}
/**
* Sets the type of the indexed document.
*/
public PutIndexedScriptRequest scriptLang(String scriptLang) {
this.scriptLang = scriptLang;
return this;
}
/**
* The id of the indexed document. If not set, will be automatically generated.
*/
public String id() {
return id;
}
/**
* Sets the id of the indexed document. If not set, will be automatically generated.
*/
public PutIndexedScriptRequest id(String id) {
this.id = id;
return this;
}
/**
* The source of the document to index, recopied to a new array if it is unsage.
*/
public BytesReference source() {
return source;
}
public BytesReference safeSource() {
if (sourceUnsafe) {
source = source.copyBytesArray();
sourceUnsafe = false;
}
return source;
}
public Map<String, Object> sourceAsMap() {
return XContentHelper.convertToMap(source, false).v2();
}
/**
* Index the Map as a {@link org.elasticsearch.client.Requests#INDEX_CONTENT_TYPE}.
*
* @param source The map to index
*/
public PutIndexedScriptRequest source(Map source) throws ElasticsearchGenerationException {
return source(source, contentType);
}
/**
* Index the Map as the provided content type.
*
* @param source The map to index
*/
public PutIndexedScriptRequest source(Map source, XContentType contentType) throws ElasticsearchGenerationException {
try {
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
builder.map(source);
return source(builder);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
}
/**
* Sets the document source to index.
* <p/>
* <p>Note, its preferable to either set it using {@link #source(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #source(byte[])}.
*/
public PutIndexedScriptRequest source(String source) {
this.source = new BytesArray(source.getBytes(Charsets.UTF_8));
this.sourceUnsafe = false;
return this;
}
/**
* Sets the content source to index.
*/
public PutIndexedScriptRequest source(XContentBuilder sourceBuilder) {
source = sourceBuilder.bytes();
sourceUnsafe = false;
return this;
}
public PutIndexedScriptRequest source(Object... source) {
if (source.length % 2 != 0) {
throw new IllegalArgumentException("The number of object passed must be even but was [" + source.length + "]");
}
try {
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
builder.startObject();
for (int i = 0; i < source.length; i++) {
builder.field(source[i++].toString(), source[i]);
}
builder.endObject();
return source(builder);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate", e);
}
}
/**
* Sets the document to index in bytes form.
*/
public PutIndexedScriptRequest source(BytesReference source, boolean unsafe) {
this.source = source;
this.sourceUnsafe = unsafe;
return this;
}
/**
* Sets the document to index in bytes form.
*/
public PutIndexedScriptRequest source(byte[] source) {
return source(source, 0, source.length);
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
*/
public PutIndexedScriptRequest source(byte[] source, int offset, int length) {
return source(source, offset, length, false);
}
/**
* Sets the document to index in bytes form.
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
* @param unsafe Is the byte array safe to be used form a different thread
*/
public PutIndexedScriptRequest source(byte[] source, int offset, int length, boolean unsafe) {
this.source = new BytesArray(source, offset, length);
this.sourceUnsafe = unsafe;
return this;
}
/**
* Sets the type of operation to perform.
*/
public PutIndexedScriptRequest opType(IndexRequest.OpType opType) {
this.opType = opType;
return this;
}
/**
* Set to <tt>true</tt> to force this index to use {@link org.elasticsearch.action.index.IndexRequest.OpType#CREATE}.
*/
public PutIndexedScriptRequest create(boolean create) {
if (create) {
return opType(IndexRequest.OpType.CREATE);
} else {
return opType(IndexRequest.OpType.INDEX);
}
}
/**
* The type of operation to perform.
*/
public IndexRequest.OpType opType() {
return this.opType;
}
/**
* Sets the version, which will cause the index operation to only be performed if a matching
* version exists and no changes happened on the doc since then.
*/
public PutIndexedScriptRequest version(long version) {
this.version = version;
return this;
}
public long version() {
return this.version;
}
/**
* Sets the versioning type. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}.
*/
public PutIndexedScriptRequest versionType(VersionType versionType) {
this.versionType = versionType;
return this;
}
public VersionType versionType() {
return this.versionType;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
scriptLang = in.readString();
id = in.readOptionalString();
source = in.readBytesReference();
sourceUnsafe = false;
opType = IndexRequest.OpType.fromId(in.readByte());
version = Versions.readVersion(in);
versionType = VersionType.fromValue(in.readByte());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(scriptLang);
out.writeOptionalString(id);
out.writeBytesReference(source);
out.writeByte(opType.id());
Versions.writeVersion(version, out);
out.writeByte(versionType.getValue());
}
@Override
public String toString() {
String sSource = "_na_";
try {
sSource = XContentHelper.convertToJson(source, false);
} catch (Exception e) {
// ignore
}
return "index {[" + ScriptService.SCRIPT_INDEX + "][" + scriptLang + "][" + id + "], source[" + sSource + "]}";
}
}

View File

@ -0,0 +1,230 @@
/*
* 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.indexedscripts.put;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import java.util.Map;
/**
* An index document action request builder.
*/
public class PutIndexedScriptRequestBuilder extends ActionRequestBuilder<PutIndexedScriptRequest, PutIndexedScriptResponse, PutIndexedScriptRequestBuilder, Client> {
public PutIndexedScriptRequestBuilder(Client client) {
super(client, new PutIndexedScriptRequest());
}
/**
* Sets the type to index the document to.
*/
public PutIndexedScriptRequestBuilder setScriptLang(String scriptLang) {
request.scriptLang(scriptLang);
return this;
}
/**
* Sets the id to index the document under. Optional, and if not set, one will be automatically
* generated.
*/
public PutIndexedScriptRequestBuilder setId(String id) {
request.id(id);
return this;
}
/**
* Sets the source.
*/
public PutIndexedScriptRequestBuilder setSource(BytesReference source, boolean unsafe) {
request.source(source, unsafe);
return this;
}
/**
* Sets the source.
*/
public PutIndexedScriptRequestBuilder setSource(BytesReference source) {
request.source(source, false);
return this;
}
/**
* Index the Map as a JSON.
*
* @param source The map to index
*/
public PutIndexedScriptRequestBuilder setSource(Map<String, Object> source) {
request.source(source);
return this;
}
/**
* Index the Map as the provided content type.
*
* @param source The map to index
*/
public PutIndexedScriptRequestBuilder setSource(Map<String, Object> source, XContentType contentType) {
request.source(source, contentType);
return this;
}
/**
* Sets the document source to index.
* <p/>
* <p>Note, its preferable to either set it using {@link #setSource(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #setSource(byte[])}.
*/
public PutIndexedScriptRequestBuilder setSource(String source) {
request.source(source);
return this;
}
/**
* Sets the content source to index.
*/
public PutIndexedScriptRequestBuilder setSource(XContentBuilder sourceBuilder) {
request.source(sourceBuilder);
return this;
}
/**
* Sets the document to index in bytes form.
*/
public PutIndexedScriptRequestBuilder setSource(byte[] source) {
request.source(source);
return this;
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
*/
public PutIndexedScriptRequestBuilder setSource(byte[] source, int offset, int length) {
request.source(source, offset, length);
return this;
}
/**
* Sets the document to index in bytes form.
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
* @param unsafe Is the byte array safe to be used form a different thread
*/
public PutIndexedScriptRequestBuilder setSource(byte[] source, int offset, int length, boolean unsafe) {
request.source(source, offset, length, unsafe);
return this;
}
/**
* Constructs a simple document with a field name and value pairs.
* <b>Note: the number of objects passed to this method must be an even number.</b>
*/
public PutIndexedScriptRequestBuilder setSource(Object... source) {
request.source(source);
return this;
}
/**
* The content type that will be used to generate a document from user provided objects (like Map).
*/
public PutIndexedScriptRequestBuilder setContentType(XContentType contentType) {
request.contentType(contentType);
return this;
}
/**
* Sets the type of operation to perform.
*/
public PutIndexedScriptRequestBuilder setOpType(IndexRequest.OpType opType) {
request.opType(opType);
return this;
}
/**
* Sets a string representation of the {@link #setOpType(org.elasticsearch.action.index.IndexRequest.OpType)}. Can
* be either "index" or "create".
*/
public PutIndexedScriptRequestBuilder setOpType(String opType) {
request.opType(IndexRequest.OpType.fromString(opType));
return this;
}
/**
* Set to <tt>true</tt> to force this index to use {@link org.elasticsearch.action.index.IndexRequest.OpType#CREATE}.
*/
public PutIndexedScriptRequestBuilder setCreate(boolean create) {
request.create(create);
return this;
}
/**
* Sets the version, which will cause the index operation to only be performed if a matching
* version exists and no changes happened on the doc since then.
*/
public PutIndexedScriptRequestBuilder setVersion(long version) {
request.version(version);
return this;
}
/**
* Sets the versioning type. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}.
*/
public PutIndexedScriptRequestBuilder setVersionType(VersionType versionType) {
request.versionType(versionType);
return this;
}
@Override
protected void doExecute(final ActionListener<PutIndexedScriptResponse> listener) {
client.putIndexedScript(request, listener);
/*
try {
scriptService.putScriptToIndex(client, request.safeSource(), request.id(), request.scriptLang(), null, request.opType().toString(), new ActionListener<IndexResponse>() {
@Override
public void onResponse(IndexResponse indexResponse) {
listener.onResponse(new PutIndexedScriptResponse(indexResponse.getType(),indexResponse.getId(),indexResponse.getVersion(),indexResponse.isCreated()));
}
@Override
public void onFailure(Throwable e) {
listener.onFailure(e);
}
});
} catch (IOException ioe) {
listener.onFailure(ioe);
}
*/
}
}

View File

@ -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.indexedscripts.put;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
/**
* A response of an index operation,
*
* @see PutIndexedScriptRequest
* @see org.elasticsearch.client.Client#putIndexedScript(PutIndexedScriptRequest)
*/
public class PutIndexedScriptResponse extends ActionResponse {
private String index;
private String id;
private String scriptLang;
private long version;
private boolean created;
public PutIndexedScriptResponse() {
}
public PutIndexedScriptResponse(String type, String id, long version, boolean created) {
this.index = ScriptService.SCRIPT_INDEX;
this.id = id;
this.scriptLang = type;
this.version = version;
this.created = created;
}
/**
* The index the document was indexed into.
*/
public String getIndex() {
return this.index;
}
/**
* The type of the document indexed.
*/
public String getScriptLang() {
return this.scriptLang;
}
/**
* The id of the document indexed.
*/
public String getId() {
return this.id;
}
/**
* Returns the current version of the doc indexed.
*/
public long getVersion() {
return this.version;
}
/**
* Returns true if the document was created, false if updated.
*/
public boolean isCreated() {
return this.created;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
index = ScriptService.SCRIPT_INDEX;
scriptLang = in.readString();
id = in.readString();
version = in.readLong();
created = in.readBoolean();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(scriptLang);
out.writeString(id);
out.writeLong(version);
out.writeBoolean(created);
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.indexedscripts.put;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.DelegatingActionListener;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
/**
* Performs the put indexed script operation.
*/
public class TransportPutIndexedScriptAction extends HandledTransportAction<PutIndexedScriptRequest, PutIndexedScriptResponse> {
private ScriptService scriptService;
private Client client;
@Inject
public TransportPutIndexedScriptAction(Settings settings, ThreadPool threadPool,
ScriptService scriptService, Client client,
TransportService transportService) {
super(settings,threadPool, transportService, PutIndexedScriptAction.NAME);
this.client = client;
this.scriptService = scriptService;
}
@Override
public PutIndexedScriptRequest newRequestInstance(){
return new PutIndexedScriptRequest();
}
@Override
protected void doExecute(final PutIndexedScriptRequest request, final ActionListener<PutIndexedScriptResponse> listener) {
scriptService.putScriptToIndex(client, request.safeSource(), request.scriptLang(), request.id(), null, request.opType().toString(), request.version(), request.versionType(), new DelegatingActionListener<IndexResponse,PutIndexedScriptResponse>(listener) {
@Override
public PutIndexedScriptResponse getDelegatedFromInstigator(IndexResponse indexResponse){
return new PutIndexedScriptResponse(indexResponse.getType(),indexResponse.getId(),indexResponse.getVersion(),indexResponse.isCreated());
}
});
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.
*/
/**
* Index action.
*/
package org.elasticsearch.action.indexedscripts.put;

View File

@ -35,6 +35,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder;
@ -71,6 +72,7 @@ public class SearchRequest extends ActionRequest<SearchRequest> {
private BytesReference templateSource;
private boolean templateSourceUnsafe;
private String templateName;
private ScriptService.ScriptType templateType;
private Map<String, String> templateParams = Collections.emptyMap();
private BytesReference source;
@ -400,8 +402,12 @@ public class SearchRequest extends ActionRequest<SearchRequest> {
/**
* The name of the stored template
*/
public void templateName(String name) {
this.templateName = name;
public void templateName(String templateName) {
this.templateName = templateName;
}
public void templateType(ScriptService.ScriptType templateType){
this.templateType = templateType;
}
/**
@ -418,6 +424,13 @@ public class SearchRequest extends ActionRequest<SearchRequest> {
return templateName;
}
/**
* The name of the stored template
*/
public ScriptService.ScriptType templateType() {
return templateType;
}
/**
* Template parameters used for rendering
*/
@ -508,6 +521,9 @@ public class SearchRequest extends ActionRequest<SearchRequest> {
templateSourceUnsafe = false;
templateSource = in.readBytesReference();
templateName = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_1_3_0)) {
templateType = ScriptService.ScriptType.readFrom(in);
}
if (in.readBoolean()) {
templateParams = (Map<String, String>) in.readGenericValue();
}
@ -544,7 +560,9 @@ public class SearchRequest extends ActionRequest<SearchRequest> {
if (out.getVersion().onOrAfter(Version.V_1_1_0)) {
out.writeBytesReference(templateSource);
out.writeOptionalString(templateName);
if (out.getVersion().onOrAfter(Version.V_1_3_0)){
ScriptService.ScriptType.writeTo(templateType,out);
}
boolean existTemplateParams = templateParams != null;
out.writeBoolean(existTemplateParams);
if (existTemplateParams) {

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
@ -1038,6 +1039,11 @@ public class SearchRequestBuilder extends ActionRequestBuilder<SearchRequest, Se
return this;
}
public SearchRequestBuilder setTemplateType(ScriptService.ScriptType templateType) {
request.templateType(templateType);
return this;
}
public SearchRequestBuilder setTemplateParams(Map<String,String> templateParams) {
request.templateParams(templateParams);
return this;

View File

@ -0,0 +1,52 @@
/*
* 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.
*/
/*
* A Simple class to handle wrapping a response with another response
*/
package org.elasticsearch.action.support;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionResponse;
public abstract class DelegatingActionListener<Instigator extends ActionResponse, Delegated extends ActionResponse> implements ActionListener<Instigator> {
ActionListener<Delegated> delegatedActionListener;
private DelegatingActionListener(){
throw new ElasticsearchIllegalStateException("Constructor for " + DelegatingActionListener.class.toString() + " can't be called.");
}
public DelegatingActionListener(final ActionListener<Delegated> listener) {
this.delegatedActionListener = listener;
}
public abstract Delegated getDelegatedFromInstigator(Instigator response);
@Override
public final void onResponse(Instigator response) {
delegatedActionListener.onResponse(getDelegatedFromInstigator(response));
}
@Override
public final void onFailure(Throwable e) {
delegatedActionListener.onFailure(e);
}
}

View File

@ -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.support;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.BaseTransportRequestHandler;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportService;
/**
* A TransportAction that self registers a handler into the transport service
*/
public abstract class HandledTransportAction<Request extends ActionRequest, Response extends ActionResponse> extends TransportAction<Request,Response>{
/**
* Sub classes implement this call to get new instance of a Request object
* @return Request
*/
public abstract Request newRequestInstance();
@Inject
public HandledTransportAction(Settings settings, ThreadPool threadPool, TransportService transportService, String actionName){
super(settings,threadPool);
transportService.registerHandler(actionName, new TransportHandler(actionName) {
@Override
public Request newInstance(){
return newRequestInstance();
}
});
}
private abstract class TransportHandler extends BaseTransportRequestHandler<Request>{
private final String actionName;
/**
* Call to get an instance of type Request
* @return Request
*/
public abstract Request newInstance();
private TransportHandler(){
throw new ElasticsearchIllegalStateException("Default constructor of " + TransportHandler.class.toString() + " cannot be called");
}
private TransportHandler(String actionName){
this.actionName = actionName;
}
@Override
public final void messageReceived(final Request request, final TransportChannel channel) throws Exception {
// no need to use threaded listener, since we just send a response
request.listenerThreaded(false);
execute(request, new ActionListener<Response>() {
@Override
public void onResponse(Response response) {
try {
channel.sendResponse(response);
} catch (Throwable e) {
onFailure(e);
}
}
@Override
public void onFailure(Throwable e) {
try {
channel.sendResponse(e);
} catch (Exception e1) {
logger.warn("Failed to send error response for action [{}] and request [{}]",
actionName, request, e1);
}
}
});
}
@Override
public String executor() {
return ThreadPool.Names.SAME;
}
}
}

View File

@ -146,7 +146,7 @@ public class UpdateHelper extends AbstractComponent {
ctx.put("_source", sourceAndContent.v2());
try {
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptParams);
ExecutableScript script = scriptService.executable(request.scriptLang, request.script, request.scriptType, request.scriptParams);
script.setNextVar("ctx", ctx);
script.run();
// we need to unwrap the ctx...

View File

@ -26,6 +26,7 @@ import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.replication.ReplicationType;
import org.elasticsearch.action.support.single.instance.InstanceShardOperationRequest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
@ -36,6 +37,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.Map;
@ -54,6 +56,8 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
@Nullable
String script;
@Nullable
ScriptService.ScriptType scriptType;
@Nullable
String scriptLang;
@Nullable
Map<String, Object> scriptParams;
@ -191,6 +195,8 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
return this.script;
}
public ScriptService.ScriptType scriptType() { return this.scriptType; }
public Map<String, Object> scriptParams() {
return this.scriptParams;
}
@ -199,11 +205,23 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
* The script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
*/
public UpdateRequest script(String script) {
public UpdateRequest script(String script, ScriptService.ScriptType scriptType) {
this.script = script;
this.scriptType = scriptType;
return this;
}
/**
* The script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
*/
public UpdateRequest script(String script) {
this.script = script;
this.scriptType = ScriptService.ScriptType.INLINE;
return this;
}
/**
* The language of the script to execute.
*/
@ -243,8 +261,9 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
* The script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
*/
public UpdateRequest script(String script, @Nullable Map<String, Object> scriptParams) {
public UpdateRequest script(String script, ScriptService.ScriptType scriptType, @Nullable Map<String, Object> scriptParams) {
this.script = script;
this.scriptType = scriptType;
if (this.scriptParams != null) {
this.scriptParams.putAll(scriptParams);
} else {
@ -259,11 +278,13 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
*
* @param script The script to execute
* @param scriptLang The script language
* @param scriptType The script type
* @param scriptParams The script parameters
*/
public UpdateRequest script(String script, @Nullable String scriptLang, @Nullable Map<String, Object> scriptParams) {
public UpdateRequest script(String script, @Nullable String scriptLang, ScriptService.ScriptType scriptType, @Nullable Map<String, Object> scriptParams) {
this.script = script;
this.scriptLang = scriptLang;
this.scriptType = scriptType;
if (this.scriptParams != null) {
this.scriptParams.putAll(scriptParams);
} else {
@ -589,6 +610,9 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
id = in.readString();
routing = in.readOptionalString();
script = in.readOptionalString();
if( Strings.hasLength(script)) {
scriptType = ScriptService.ScriptType.readFrom(in);
}
scriptLang = in.readOptionalString();
scriptParams = in.readMap();
retryOnConflict = in.readVInt();
@ -622,6 +646,9 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
out.writeString(id);
out.writeOptionalString(routing);
out.writeOptionalString(script);
if (script != null) {
ScriptService.ScriptType.writeTo(scriptType, out);
}
out.writeOptionalString(scriptLang);
out.writeMap(scriptParams);
out.writeVInt(retryOnConflict);

View File

@ -29,6 +29,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.script.ScriptService;
import java.util.Map;
@ -78,17 +79,63 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
* The script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
* <p>
* The script works with the variable <code>ctx</code>, which is bound to the entry,
* The script works with the variable <code>ctx</code>, which is bound to the entry,
* e.g. <code>ctx._source.mycounter += 1</code>.
*
*
* @see #setScriptLang(String)
* @see #setScriptParams(Map)
*/
public UpdateRequestBuilder setScript(String script) {
request.script(script);
public UpdateRequestBuilder setScript(String script, ScriptService.ScriptType scriptType) {
request.script(script, scriptType);
return this;
}
/**
* The indexed script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
* <p>
* The script works with the variable <code>ctx</code>, which is bound to the entry,
* e.g. <code>ctx._source.mycounter += 1</code>.
*
* @see #setScriptLang(String)
* @see #setScriptParams(Map)
*/
public UpdateRequestBuilder setIndexedScript(String script) {
request.script(script, ScriptService.ScriptType.INDEXED);
return this;
}
/**
* The on disk script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
* <p>
* The script works with the variable <code>ctx</code>, which is bound to the entry,
* e.g. <code>ctx._source.mycounter += 1</code>.
*
* @see #setScriptLang(String)
* @see #setScriptParams(Map)
*/
public UpdateRequestBuilder setOnDiskScript(String script) {
request.script(script, ScriptService.ScriptType.FILE);
return this;
}
/**
* The inline script to execute. Note, make sure not to send different script each times and instead
* use script params if possible with the same (automatically compiled) script.
* <p>
* The script works with the variable <code>ctx</code>, which is bound to the entry,
* e.g. <code>ctx._source.mycounter += 1</code>.
*
* @see #setScriptLang(String)
* @see #setScriptParams(Map)
*/
public UpdateRequestBuilder setInlineScript(String script) {
request.script(script, ScriptService.ScriptType.INLINE);
return this;
}
/**
* The language of the script to execute.
* Valid options are: mvel, js, groovy, python, and native (Java)<br>

View File

@ -40,6 +40,15 @@ import org.elasticsearch.action.get.*;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptResponse;
import org.elasticsearch.action.mlt.MoreLikeThisRequest;
import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder;
import org.elasticsearch.action.percolate.*;
@ -55,8 +64,6 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.settings.Settings;
import java.io.Closeable;
/**
* A client provides a one stop interface for performing actions/operations against the cluster.
* <p/>
@ -260,6 +267,99 @@ public interface Client extends ElasticsearchClient<Client>, Releasable {
*/
GetRequestBuilder prepareGet(String index, @Nullable String type, String id);
/**
* Put an indexed script
*/
PutIndexedScriptRequestBuilder preparePutIndexedScript();
/**
* Put the indexed script
* @param scriptLang
* @param id
* @param source
* @return
*/
PutIndexedScriptRequestBuilder preparePutIndexedScript(@Nullable String scriptLang, String id, String source);
/**
* delete an indexed script
*
* @param request
* @param listener
*/
void deleteIndexedScript(DeleteIndexedScriptRequest request, ActionListener<DeleteIndexedScriptResponse> listener);
/**
* Delete an indexed script
*
* @param request The put request
* @return The result future
*/
ActionFuture<DeleteIndexedScriptResponse> deleteIndexedScript(DeleteIndexedScriptRequest request);
/**
* Delete an indexed script
*/
DeleteIndexedScriptRequestBuilder prepareDeleteIndexedScript();
/**
* Delete an indexed script
* @param scriptLang
* @param id
* @return
*/
DeleteIndexedScriptRequestBuilder prepareDeleteIndexedScript(@Nullable String scriptLang, String id);
/**
* Put an indexed script
*
* @param request
* @param listener
*/
void putIndexedScript(PutIndexedScriptRequest request, ActionListener<PutIndexedScriptResponse> listener);
/**
* Put an indexed script
*
* @param request The put request
* @return The result future
*/
ActionFuture<PutIndexedScriptResponse> putIndexedScript(PutIndexedScriptRequest request);
/**
* Get an indexed script
*/
GetIndexedScriptRequestBuilder prepareGetIndexedScript();
/**
* Get the indexed script
* @param scriptLang
* @param id
* @return
*/
GetIndexedScriptRequestBuilder prepareGetIndexedScript(@Nullable String scriptLang, String id);
/**
* Get an indexed script
*
* @param request
* @param listener
*/
void getIndexedScript(GetIndexedScriptRequest request, ActionListener<GetIndexedScriptResponse> listener);
/**
* Gets the document that was indexed from an index with a type and id.
*
* @param request The get request
* @return The result future
* @see Requests#getRequest(String)
*/
ActionFuture<GetIndexedScriptResponse> getIndexedScript(GetIndexedScriptRequest request);
/**
* Multi get documents.
*/

View File

@ -20,6 +20,7 @@
package org.elasticsearch.client.support;
import org.elasticsearch.action.*;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexAction;
import org.elasticsearch.action.bench.*;
import org.elasticsearch.action.bulk.BulkAction;
import org.elasticsearch.action.bulk.BulkRequest;
@ -46,6 +47,18 @@ import org.elasticsearch.action.index.IndexAction;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptAction;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequestBuilder;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptResponse;
import org.elasticsearch.action.mlt.MoreLikeThisAction;
import org.elasticsearch.action.mlt.MoreLikeThisRequest;
import org.elasticsearch.action.mlt.MoreLikeThisRequestBuilder;
@ -188,6 +201,112 @@ public abstract class AbstractClient implements Client {
return prepareGet().setIndex(index).setType(type).setId(id);
}
@Override
public ActionFuture<GetIndexedScriptResponse> getIndexedScript(final GetIndexedScriptRequest request) {
return execute(GetIndexedScriptAction.INSTANCE, request);
}
@Override
public void getIndexedScript(final GetIndexedScriptRequest request, final ActionListener<GetIndexedScriptResponse> listener) {
execute(GetIndexedScriptAction.INSTANCE, request, listener);
}
@Override
public GetIndexedScriptRequestBuilder prepareGetIndexedScript() {
return new GetIndexedScriptRequestBuilder(this);
}
@Override
public GetIndexedScriptRequestBuilder prepareGetIndexedScript(String scriptLang, String id) {
return prepareGetIndexedScript().setScriptLang(scriptLang).setId(id);
}
/**
* Put an indexed script
*/
@Override
public PutIndexedScriptRequestBuilder preparePutIndexedScript() {
return new PutIndexedScriptRequestBuilder(this);
}
/**
* Put the indexed script
* @param scriptLang
* @param id
* @param source
* @return
*/
@Override
public PutIndexedScriptRequestBuilder preparePutIndexedScript(@Nullable String scriptLang, String id, String source){
return PutIndexedScriptAction.INSTANCE.newRequestBuilder(this).setScriptLang(scriptLang).setId(id).setSource(source);
}
/**
* Put an indexed script
*
* @param request
* @param listener
*/
@Override
public void putIndexedScript(final PutIndexedScriptRequest request, ActionListener<PutIndexedScriptResponse> listener){
execute(PutIndexedScriptAction.INSTANCE, request, listener);
}
/**
* Put an indexed script
*
* @param request The put request
* @return The result future
*/
@Override
public ActionFuture<PutIndexedScriptResponse> putIndexedScript(final PutIndexedScriptRequest request){
return execute(PutIndexedScriptAction.INSTANCE, request);
}
/**
* delete an indexed script
*
* @param request
* @param listener
*/
@Override
public void deleteIndexedScript(DeleteIndexedScriptRequest request, ActionListener<DeleteIndexedScriptResponse> listener){
execute(DeleteIndexedScriptAction.INSTANCE, request, listener);
}
/**
* Delete an indexed script
*
* @param request The put request
* @return The result future
*/
public ActionFuture<DeleteIndexedScriptResponse> deleteIndexedScript(DeleteIndexedScriptRequest request){
return execute(DeleteIndexedScriptAction.INSTANCE, request);
}
/**
* Delete an indexed script
*/
public DeleteIndexedScriptRequestBuilder prepareDeleteIndexedScript(){
return DeleteIndexedScriptAction.INSTANCE.newRequestBuilder(this);
}
/**
* Delete an indexed script
* @param scriptLang
* @param id
* @return
*/
public DeleteIndexedScriptRequestBuilder prepareDeleteIndexedScript(@Nullable String scriptLang, String id){
return prepareDeleteIndexedScript().setScriptLang(scriptLang).setId(id);
}
@Override
public ActionFuture<MultiGetResponse> multiGet(final MultiGetRequest request) {
return execute(MultiGetAction.INSTANCE, request);

View File

@ -57,7 +57,6 @@ public class InternalTransportClient extends AbstractClient {
this.threadPool = threadPool;
this.nodesService = nodesService;
this.adminClient = adminClient;
MapBuilder<Action, TransportActionNodeProxy> actionsBuilder = new MapBuilder<>();
for (GenericAction action : actions.values()) {
if (action instanceof Action) {

View File

@ -25,6 +25,7 @@ import com.google.common.collect.Iterables;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.UnicodeUtil;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.FastStringReader;
import org.elasticsearch.common.util.CollectionUtils;
@ -207,6 +208,18 @@ public class Strings {
return (str != null && str.length() > 0);
}
/**
* Check that the given BytesReference is neither <code>null</code> nor of length 0
* Note: Will return <code>true</code> for a BytesReference that purely consists of whitespace.
*
* @param bytesReference the BytesReference to check (may be <code>null</code>)
* @return <code>true</code> if the BytesReference is not null and has length
* @see #hasLength(CharSequence)
*/
public static boolean hasLength(BytesReference bytesReference) {
return (bytesReference != null && bytesReference.length() > 0);
}
/**
* Check that the given String is neither <code>null</code> nor of length 0.
* Note: Will return <code>true</code> for a String that purely consists of whitespace.

View File

@ -60,6 +60,7 @@ import org.elasticsearch.index.similarity.SimilarityLookupService;
import org.elasticsearch.indices.InvalidTypeNameException;
import org.elasticsearch.indices.TypeMissingException;
import org.elasticsearch.percolator.PercolatorService;
import org.elasticsearch.script.ScriptService;
import java.io.File;
import java.io.IOException;
@ -104,6 +105,7 @@ public class MapperService extends AbstractIndexComponent {
private volatile String defaultMappingSource;
private volatile String defaultPercolatorMappingSource;
private volatile Map<String, DocumentMapper> mappers = ImmutableMap.of();
private final Object typeMutex = new Object();
@ -136,36 +138,30 @@ public class MapperService extends AbstractIndexComponent {
this.dynamic = componentSettings.getAsBoolean("dynamic", true);
String defaultMappingLocation = componentSettings.get("default_mapping_location");
URL defaultMappingUrl;
if (defaultMappingLocation == null) {
try {
defaultMappingUrl = environment.resolveConfig("default-mapping.json");
} catch (FailedToResolveConfigException e) {
// not there, default to the built in one
defaultMappingUrl = indexSettings.getClassLoader().getResource("org/elasticsearch/index/mapper/default-mapping.json");
if (defaultMappingUrl == null) {
defaultMappingUrl = MapperService.class.getClassLoader().getResource("org/elasticsearch/index/mapper/default-mapping.json");
}
}
final URL defaultMappingUrl;
if (index.getName().equals(ScriptService.SCRIPT_INDEX)){
defaultMappingUrl = getMappingUrl(indexSettings, environment, defaultMappingLocation,"script-index-defaults.json","org/elasticsearch/index/mapper/script-index-defaults.json");
} else {
try {
defaultMappingUrl = environment.resolveConfig(defaultMappingLocation);
} catch (FailedToResolveConfigException e) {
// not there, default to the built in one
try {
defaultMappingUrl = new File(defaultMappingLocation).toURI().toURL();
} catch (MalformedURLException e1) {
throw new FailedToResolveConfigException("Failed to resolve dynamic mapping location [" + defaultMappingLocation + "]");
}
}
defaultMappingUrl = getMappingUrl(indexSettings, environment, defaultMappingLocation,"default-mapping.json","org/elasticsearch/index/mapper/default-mapping.json");
}
if (defaultMappingUrl == null) {
logger.info("failed to find default-mapping.json in the classpath, using the default template");
defaultMappingSource = "{\n" +
" \"_default_\":{\n" +
" }\n" +
"}";
if (index.getName().equals(ScriptService.SCRIPT_INDEX)){
defaultMappingSource = "{" +
"\"_default_\": {" +
"\"properties\": {" +
"\"script\": { \"enabled\": false }," +
"\"template\": { \"enabled\": false }" +
"}" +
"}" +
"}";
} else {
defaultMappingSource = "{\n" +
" \"_default_\":{\n" +
" }\n" +
"}";
}
} else {
try {
defaultMappingSource = Streams.copyToString(new InputStreamReader(defaultMappingUrl.openStream(), Charsets.UTF_8));
@ -216,6 +212,33 @@ public class MapperService extends AbstractIndexComponent {
}
}
private URL getMappingUrl(Settings indexSettings, Environment environment, String mappingLocation, String configString, String resourceLocation) {
URL mappingUrl;
if (mappingLocation == null) {
try {
mappingUrl = environment.resolveConfig(configString);
} catch (FailedToResolveConfigException e) {
// not there, default to the built in one
mappingUrl = indexSettings.getClassLoader().getResource(resourceLocation);
if (mappingUrl == null) {
mappingUrl = MapperService.class.getClassLoader().getResource(resourceLocation);
}
}
} else {
try {
mappingUrl = environment.resolveConfig(mappingLocation);
} catch (FailedToResolveConfigException e) {
// not there, default to the built in one
try {
mappingUrl = new File(mappingLocation).toURI().toURL();
} catch (MalformedURLException e1) {
throw new FailedToResolveConfigException("Failed to resolve dynamic mapping location [" + mappingLocation + "]");
}
}
}
return mappingUrl;
}
public void close() {
for (DocumentMapper documentMapper : mappers.values()) {
documentMapper.close();
@ -417,7 +440,7 @@ public class MapperService extends AbstractIndexComponent {
String defaultMappingSource;
if (PercolatorService.TYPE_NAME.equals(mappingType)) {
defaultMappingSource = this.defaultPercolatorMappingSource;
} else {
} else {
defaultMappingSource = this.defaultMappingSource;
}
return documentParser.parseCompressed(mappingType, mappingSource, applyDefault ? defaultMappingSource : null);

View File

@ -0,0 +1,16 @@
{
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : "0-all"
}
"mappings": {
"_default_": {
"properties": {
"script": { "enabled": false },
"template": { "enabled": false }
}
}
}
}

View File

@ -70,6 +70,8 @@ public class ScriptFilterParser implements FilterParser {
String filterName = null;
String currentFieldName = null;
ScriptService.ScriptType scriptType = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
@ -82,6 +84,13 @@ public class ScriptFilterParser implements FilterParser {
} else if (token.isValue()) {
if ("script".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if ("id".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if ("file".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
} else if ("_name".equals(currentFieldName)) {
@ -103,7 +112,7 @@ public class ScriptFilterParser implements FilterParser {
params = newHashMap();
}
Filter filter = new ScriptFilter(scriptLang, script, params, parseContext.scriptService(), parseContext.lookup());
Filter filter = new ScriptFilter(scriptLang, script, scriptType, params, parseContext.scriptService(), parseContext.lookup());
if (cache) {
filter = parseContext.cacheFilter(filter, cacheKey);
}
@ -121,11 +130,13 @@ public class ScriptFilterParser implements FilterParser {
private final SearchScript searchScript;
public ScriptFilter(String scriptLang, String script, Map<String, Object> params, ScriptService scriptService, SearchLookup searchLookup) {
private final ScriptService.ScriptType scriptType;
public ScriptFilter(String scriptLang, String script, ScriptService.ScriptType scriptType, Map<String, Object> params, ScriptService scriptService, SearchLookup searchLookup) {
this.script = script;
this.params = params;
this.searchScript = scriptService.search(searchLookup, scriptLang, script, newHashMap(params));
this.scriptType = scriptType;
this.searchScript = scriptService.search(searchLookup, scriptLang, script, scriptType, newHashMap(params));
}
@Override

View File

@ -18,7 +18,10 @@
*/
package org.elasticsearch.index.query;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import java.io.IOException;
import java.util.Map;
@ -33,19 +36,45 @@ public class TemplateQueryBuilder extends BaseQueryBuilder {
/** Template to fill.*/
private String template;
private ScriptService.ScriptType templateType;
/**
* @param template the template to use for that query.
* @param vars the parameters to fill the template with.
* */
public TemplateQueryBuilder(String template, Map<String, Object> vars) {
this(template, ScriptService.ScriptType.INLINE, vars);
}
/**
* @param template the template to use for that query.
* @param vars the parameters to fill the template with.
* @param templateType what kind of template (INLINE,FILE,ID)
* */
public TemplateQueryBuilder(String template, ScriptService.ScriptType templateType, Map<String, Object> vars) {
this.template = template;
this.vars = vars;
this.vars =vars;
this.templateType = templateType;
}
@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(TemplateQueryParser.NAME);
builder.field(TemplateQueryParser.QUERY, template);
String fieldname;
switch(templateType){
case FILE:
fieldname = "file";
break;
case INDEXED:
fieldname = "id";
break;
case INLINE:
fieldname = TemplateQueryParser.QUERY;
break;
default:
throw new ElasticsearchIllegalArgumentException("Unknown template type " + templateType);
}
builder.field(fieldname, template);
builder.field(TemplateQueryParser.PARAMS, vars);
builder.endObject();
}

View File

@ -19,9 +19,12 @@
package org.elasticsearch.index.query;
import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
@ -29,6 +32,7 @@ import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
@ -46,6 +50,13 @@ public class TemplateQueryParser implements QueryParser {
private final ScriptService scriptService;
private final static Map<String,ScriptService.ScriptType> parametersToTypes = new HashMap<>();
static {
parametersToTypes.put("query",ScriptService.ScriptType.INLINE);
parametersToTypes.put("file",ScriptService.ScriptType.FILE);
parametersToTypes.put("id",ScriptService.ScriptType.INDEXED);
}
@Inject
public TemplateQueryParser(ScriptService scriptService) {
this.scriptService = scriptService;
@ -66,8 +77,9 @@ public class TemplateQueryParser implements QueryParser {
@Nullable
public Query parse(QueryParseContext parseContext) throws IOException {
XContentParser parser = parseContext.parser();
TemplateContext templateContext = parse(parser, QUERY, PARAMS);
ExecutableScript executable = this.scriptService.executable("mustache", templateContext.template(), templateContext.params());
TemplateContext templateContext = parse(parser, PARAMS, parametersToTypes);
ExecutableScript executable = this.scriptService.executable("mustache", templateContext.template(), templateContext.scriptType(), templateContext.params());
BytesReference querySource = (BytesReference) executable.run();
try (XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(querySource)) {
@ -78,16 +90,34 @@ public class TemplateQueryParser implements QueryParser {
}
}
public static TemplateContext parse(XContentParser parser, String templateFieldname, String paramsFieldname) throws IOException {
public static TemplateContext parse(XContentParser parser, String paramsFieldname, String ... parameters) throws IOException {
Map<String,ScriptService.ScriptType> parameterMap = new HashMap<>(parametersToTypes);
for (String parameter : parameters) {
parameterMap.put(parameter, ScriptService.ScriptType.INLINE);
}
return parse(parser,paramsFieldname,parameterMap);
}
public static TemplateContext parse(XContentParser parser, String paramsFieldname) throws IOException {
return parse(parser,paramsFieldname,parametersToTypes);
}
public static TemplateContext parse(XContentParser parser, String paramsFieldname, Map<String,ScriptService.ScriptType> parameterMap) throws IOException {
Map<String, Object> params = null;
String templateNameOrTemplateContent = null;
String currentFieldName = null;
XContentParser.Token token;
ScriptService.ScriptType type = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (templateFieldname.equals(currentFieldName)) {
} else if (parameterMap.containsKey(currentFieldName)) {
type = parameterMap.get(currentFieldName);
if (token == XContentParser.Token.START_OBJECT && !parser.hasTextCharacters()) {
XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent());
builder.copyCurrentStructure(parser);
@ -100,16 +130,18 @@ public class TemplateQueryParser implements QueryParser {
}
}
return new TemplateContext(templateNameOrTemplateContent, params);
return new TemplateContext(type, templateNameOrTemplateContent, params);
}
public static class TemplateContext {
private Map<String, Object> params;
private String template;
private ScriptService.ScriptType type;
public TemplateContext(String templateName, Map<String, Object> params) {
public TemplateContext(ScriptService.ScriptType type, String template, Map<String, Object> params) {
this.params = params;
this.template = templateName;
this.template = template;
this.type = type;
}
public Map<String, Object> params() {
@ -119,5 +151,14 @@ public class TemplateQueryParser implements QueryParser {
public String template() {
return template;
}
public ScriptService.ScriptType scriptType(){
return type;
}
@Override
public String toString(){
return type + " " + template;
}
}
}

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryParsingException;
import org.elasticsearch.index.query.functionscore.ScoreFunctionParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import java.io.IOException;
@ -55,7 +56,7 @@ public class ScriptScoreFunctionParser implements ScoreFunctionParser {
String script = null;
String scriptLang = null;
Map<String, Object> vars = null;
ScriptService.ScriptType scriptType = null;
String currentFieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -70,6 +71,12 @@ public class ScriptScoreFunctionParser implements ScoreFunctionParser {
} else if (token.isValue()) {
if ("script".equals(currentFieldName)) {
script = parser.text();
} else if ("id".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if ("file".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
} else {
@ -84,7 +91,7 @@ public class ScriptScoreFunctionParser implements ScoreFunctionParser {
SearchScript searchScript;
try {
searchScript = parseContext.scriptService().search(parseContext.lookup(), scriptLang, script, vars);
searchScript = parseContext.scriptService().search(parseContext.lookup(), scriptLang, script, scriptType, vars);
return new ScriptScoreFunction(script, vars, searchScript);
} catch (Exception e) {
throw new QueryParsingException(parseContext.index(), NAMES[0] + " the script could not be loaded", e);

View File

@ -93,11 +93,17 @@ import org.elasticsearch.rest.action.main.RestMainAction;
import org.elasticsearch.rest.action.mlt.RestMoreLikeThisAction;
import org.elasticsearch.rest.action.percolate.RestMultiPercolateAction;
import org.elasticsearch.rest.action.percolate.RestPercolateAction;
import org.elasticsearch.rest.action.script.RestDeleteIndexedScriptAction;
import org.elasticsearch.rest.action.script.RestGetIndexedScriptAction;
import org.elasticsearch.rest.action.script.RestPutIndexedScriptAction;
import org.elasticsearch.rest.action.search.RestClearScrollAction;
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.rest.action.search.RestSearchScrollAction;
import org.elasticsearch.rest.action.suggest.RestSuggestAction;
import org.elasticsearch.rest.action.template.RestDeleteSearchTemplateAction;
import org.elasticsearch.rest.action.template.RestGetSearchTemplateAction;
import org.elasticsearch.rest.action.template.RestPutSearchTemplateAction;
import org.elasticsearch.rest.action.termvector.RestMultiTermVectorsAction;
import org.elasticsearch.rest.action.termvector.RestTermVectorAction;
import org.elasticsearch.rest.action.update.RestUpdateAction;
@ -213,6 +219,17 @@ public class RestActionModule extends AbstractModule {
// Benchmark API
bind(RestBenchAction.class).asEagerSingleton();
// Templates API
bind(RestGetSearchTemplateAction.class).asEagerSingleton();
bind(RestPutSearchTemplateAction.class).asEagerSingleton();
bind(RestDeleteSearchTemplateAction.class).asEagerSingleton();
// Scripts API
bind(RestGetIndexedScriptAction.class).asEagerSingleton();
bind(RestPutIndexedScriptAction.class).asEagerSingleton();
bind(RestDeleteIndexedScriptAction.class).asEagerSingleton();
// cat API
Multibinder<AbstractCatAction> catActionMultibinder = Multibinder.newSetBinder(binder(), AbstractCatAction.class);
catActionMultibinder.addBinding().to(RestAllocationAction.class).asEagerSingleton();

View File

@ -19,6 +19,7 @@
package org.elasticsearch.rest.action.index;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.action.WriteConsistencyLevel;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
@ -85,14 +86,12 @@ public class RestIndexAction extends BaseRestHandler {
indexRequest.versionType(VersionType.fromString(request.param("version_type"), indexRequest.versionType()));
String sOpType = request.param("op_type");
if (sOpType != null) {
if ("index".equals(sOpType)) {
indexRequest.opType(IndexRequest.OpType.INDEX);
} else if ("create".equals(sOpType)) {
indexRequest.opType(IndexRequest.OpType.CREATE);
} else {
try {
indexRequest.opType(IndexRequest.OpType.fromString(sOpType));
} catch (ElasticsearchIllegalArgumentException eia){
try {
XContentBuilder builder = channel.newBuilder();
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder.startObject().field("error", "opType [" + sOpType + "] not allowed, either [index] or [create] are allowed").endObject()));
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder.startObject().field("error", eia.getMessage()).endObject()));
} catch (IOException e1) {
logger.warn("Failed to send response", e1);
return;

View File

@ -0,0 +1,82 @@
/*
* 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.script;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.script.ScriptService;
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
public class RestDeleteIndexedScriptAction extends BaseRestHandler {
private ScriptService scriptService;
@Inject
public RestDeleteIndexedScriptAction(Settings settings, Client client,
ScriptService scriptService, RestController controller) {
super(settings, client);
controller.registerHandler(DELETE, "/_search/script/{lang}/{id}", this);
this.scriptService = scriptService;
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
final String id = request.param("id");
final long version = request.paramAsLong("version", Versions.MATCH_ANY);
scriptService.deleteScriptFromIndex(client,request.param("lang"), id, version, new RestBuilderListener<DeleteResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteResponse result, XContentBuilder builder) throws Exception {
builder.startObject()
.field(Fields.FOUND, result.isFound())
.field(Fields._INDEX, result.getIndex())
.field(Fields._TYPE, result.getType())
.field(Fields._ID, result.getId())
.field(Fields._VERSION, result.getVersion())
.endObject();
RestStatus status = OK;
if (!result.isFound()) {
status = NOT_FOUND;
}
return new BytesRestResponse(status, builder);
}
});
}
static final class Fields {
static final XContentBuilderString FOUND = new XContentBuilderString("found");
static final XContentBuilderString _INDEX = new XContentBuilderString("_index");
static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
static final XContentBuilderString _ID = new XContentBuilderString("_id");
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.script;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestResponseListener;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
/**
*
*/
public class RestGetIndexedScriptAction extends BaseRestHandler {
@Inject
public RestGetIndexedScriptAction(Settings settings, Client client,
ScriptService scriptService, RestController controller) {
super(settings, client);
controller.registerHandler(GET, "/_search/script/{lang}/{id}", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
final GetIndexedScriptRequest getRequest = new GetIndexedScriptRequest(ScriptService.SCRIPT_INDEX, request.param("lang"), request.param("id"));
RestResponseListener<GetIndexedScriptResponse> responseListener = new RestResponseListener<GetIndexedScriptResponse>(channel) {
@Override
public RestResponse buildResponse(GetIndexedScriptResponse response) throws Exception {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
if (!response.isExists()) {
return new BytesRestResponse(NOT_FOUND, builder);
} else {
try{
String script = response.getScript();
builder.startObject();
builder.field("script",script);
builder.endObject();
return new BytesRestResponse(OK, builder);
} catch( IOException|ClassCastException e ){
throw new ElasticsearchIllegalStateException("Unable to parse " + response.getScript() + " as json",e);
}
}
}
};
client.getIndexedScript(getRequest, responseListener);
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.script;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestRequest.Method.PUT;
import static org.elasticsearch.rest.RestStatus.*;
/**
*
*/
public class RestPutIndexedScriptAction extends BaseRestHandler {
@Inject
public RestPutIndexedScriptAction(Settings settings, Client client, RestController controller) {
super(settings, client);
//controller.registerHandler(GET, "/template", this);
controller.registerHandler(POST, "/_search/script/{lang}/{id}", this);
controller.registerHandler(PUT, "/_search/script/{lang}/{id}", this);
controller.registerHandler(PUT, "/_search/script/{lang}/{id}/_create", new CreateHandler(settings, client));
controller.registerHandler(POST, "/_search/script/{lang}/{id}/_create", new CreateHandler(settings, client));
}
final class CreateHandler extends BaseRestHandler {
protected CreateHandler(Settings settings, final Client client) {
super(settings, client);
}
@Override
public void handleRequest(RestRequest request, RestChannel channel, final Client client) {
request.params().put("op_type", "create");
RestPutIndexedScriptAction.this.handleRequest(request, channel, client);
}
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
PutIndexedScriptRequest putRequest = new PutIndexedScriptRequest(request.param("lang"), request.param("id"));
putRequest.listenerThreaded(false);
putRequest.source(request.content(), request.contentUnsafe());
String sOpType = request.param("op_type");
if (sOpType != null) {
try {
putRequest.opType(IndexRequest.OpType.fromString(sOpType));
} catch (ElasticsearchIllegalArgumentException eia){
try {
XContentBuilder builder = channel.newBuilder();
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder.startObject().field("error", eia.getMessage()).endObject()));
return;
} catch (IOException e1) {
logger.warn("Failed to send response", e1);
return;
}
}
}
client.putIndexedScript(putRequest, new RestBuilderListener<PutIndexedScriptResponse>(channel) {
@Override
public RestResponse buildResponse(PutIndexedScriptResponse response, XContentBuilder builder) throws Exception {
builder.startObject()
.field(Fields._ID, response.getId())
.field(Fields._VERSION, response.getVersion())
.field(Fields.CREATED, response.isCreated());
builder.endObject();
RestStatus status = OK;
if (response.isCreated()) {
status = CREATED;
}
return new BytesRestResponse(status, builder);
}
});
}
static final class Fields {
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
static final XContentBuilderString _ID = new XContentBuilderString("_id");
static final XContentBuilderString CREATED = new XContentBuilderString("created");
}
}

View File

@ -0,0 +1,80 @@
/*
* 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.template;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.script.ScriptService;
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
public class RestDeleteSearchTemplateAction extends BaseRestHandler {
private ScriptService scriptService;
@Inject
public RestDeleteSearchTemplateAction(Settings settings, Client client, RestController controller, ScriptService scriptService) {
super(settings, client);
controller.registerHandler(DELETE, "/_search/template/{id}", this);
this.scriptService = scriptService;
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
final String id = request.param("id");
final long version = request.paramAsLong("version", Versions.MATCH_ANY);
scriptService.deleteScriptFromIndex(client,"mustache", id, version, new RestBuilderListener<DeleteResponse>(channel) {
@Override
public RestResponse buildResponse(DeleteResponse result, XContentBuilder builder) throws Exception {
builder.startObject()
.field(Fields.FOUND, result.isFound())
.field(Fields._INDEX, result.getIndex())
.field(Fields._TYPE, result.getType())
.field(Fields._ID, result.getId())
.field(Fields._VERSION, result.getVersion())
.endObject();
RestStatus status = OK;
if (!result.isFound()) {
status = NOT_FOUND;
}
return new BytesRestResponse(status, builder);
}
});
}
static final class Fields {
static final XContentBuilderString FOUND = new XContentBuilderString("found");
static final XContentBuilderString _INDEX = new XContentBuilderString("_index");
static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
static final XContentBuilderString _ID = new XContentBuilderString("_id");
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
}
}

View File

@ -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.rest.action.template;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestResponseListener;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
/**
*
*/
public class RestGetSearchTemplateAction extends BaseRestHandler {
@Inject
public RestGetSearchTemplateAction(Settings settings, Client client,
RestController controller, ScriptService scriptService) {
super(settings, client);
controller.registerHandler(GET, "/_search/template/{id}", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
final GetIndexedScriptRequest getRequest = new GetIndexedScriptRequest(ScriptService.SCRIPT_INDEX, "mustache", request.param("id"));
RestResponseListener<GetIndexedScriptResponse> responseListener = new RestResponseListener<GetIndexedScriptResponse>(channel) {
@Override
public RestResponse buildResponse(GetIndexedScriptResponse response) throws Exception {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
if (!response.isExists()) {
return new BytesRestResponse(NOT_FOUND, builder);
} else {
try{
String templateString = response.getScript();
builder.startObject();
builder.field("template",templateString);
builder.endObject();
return new BytesRestResponse(OK, builder);
} catch( IOException|ClassCastException e ){
throw new ElasticsearchIllegalStateException("Unable to parse " + response.getScript() + " as json",e);
}
}
}
};
client.getIndexedScript(getRequest, responseListener);
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.template;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptRequest;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.POST;
import static org.elasticsearch.rest.RestRequest.Method.PUT;
import static org.elasticsearch.rest.RestStatus.CREATED;
import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.RestStatus.BAD_REQUEST;
/**
*
*/
public class RestPutSearchTemplateAction extends BaseRestHandler {
@Inject
public RestPutSearchTemplateAction(Settings settings, Client client, RestController controller) {
super(settings, 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, client));
controller.registerHandler(POST, "/_search/template/{id}/_create", new CreateHandler(settings, client));
}
final class CreateHandler extends BaseRestHandler {
protected CreateHandler(Settings settings, final 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
public void handleRequest(final RestRequest request, final RestChannel channel, Client client) {
PutIndexedScriptRequest putRequest = new PutIndexedScriptRequest("mustache", request.param("id"));
putRequest.listenerThreaded(false);
putRequest.source(request.content(), request.contentUnsafe());
String sOpType = request.param("op_type");
if (sOpType != null) {
try {
putRequest.opType(IndexRequest.OpType.fromString(sOpType));
} catch (ElasticsearchIllegalArgumentException eia){
try {
XContentBuilder builder = channel.newBuilder();
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, builder.startObject().field("error", eia.getMessage()).endObject()));
return;
} catch (IOException e1) {
logger.warn("Failed to send response", e1);
return;
}
}
}
client.putIndexedScript(putRequest, new RestBuilderListener<PutIndexedScriptResponse>(channel) {
@Override
public RestResponse buildResponse(PutIndexedScriptResponse response, XContentBuilder builder) throws Exception {
builder.startObject()
.field(Fields._ID, response.getId())
.field(Fields._VERSION, response.getVersion())
.field(Fields.CREATED, response.isCreated());
builder.endObject();
RestStatus status = OK;
if (response.isCreated()) {
status = CREATED;
}
return new BytesRestResponse(status, builder);
}
});
}
static final class Fields {
static final XContentBuilderString _VERSION = new XContentBuilderString("_version");
static final XContentBuilderString _ID = new XContentBuilderString("_id");
static final XContentBuilderString CREATED = new XContentBuilderString("created");
}
}

View File

@ -34,6 +34,7 @@ import org.elasticsearch.index.VersionType;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestActions;
import org.elasticsearch.rest.action.support.RestBuilderListener;
import org.elasticsearch.script.ScriptService;
import java.util.Map;
@ -68,7 +69,13 @@ public class RestUpdateAction extends BaseRestHandler {
updateRequest.consistencyLevel(WriteConsistencyLevel.fromString(consistencyLevel));
}
updateRequest.docAsUpsert(request.paramAsBoolean("doc_as_upsert", updateRequest.docAsUpsert()));
updateRequest.script(request.param("script"));
if( request.hasParam("script") ) {
updateRequest.script(request.param("script"), ScriptService.ScriptType.INLINE);
} else if( request.hasParam("script_id") ) {
updateRequest.script(request.param("script_id"), ScriptService.ScriptType.INDEXED);
} else if( request.hasParam("script_file") ) {
updateRequest.script(request.param("script_file"), ScriptService.ScriptType.FILE);
}
updateRequest.scriptLang(request.param("lang"));
for (Map.Entry<String, String> entry : request.params().entrySet()) {
if (entry.getKey().startsWith("sp_")) {

View File

@ -24,17 +24,38 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.index.fielddata.IndexFieldDataService;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.TemplateQueryParser;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.watcher.FileChangesListener;
import org.elasticsearch.watcher.FileWatcher;
@ -58,8 +79,11 @@ public class ScriptService extends AbstractComponent {
public static final String DEFAULT_SCRIPTING_LANGUAGE_SETTING = "script.default_lang";
public static final String DISABLE_DYNAMIC_SCRIPTING_SETTING = "script.disable_dynamic";
public static final String DISABLE_DYNAMIC_SCRIPTING_DEFAULT = "sandbox";
public static final String SCRIPT_INDEX = ".scripts";
private final String defaultLang;
//Make static so that it has visibility in IndexedScript
//Looked up from settings in ctor
private static String defaultLang = "groovy";
private final ImmutableMap<String, ScriptEngineService> scriptEngines;
@ -70,6 +94,8 @@ public class ScriptService extends AbstractComponent {
private final DynamicScriptDisabling dynamicScriptingDisabled;
private Client client = null;
/**
* Enum defining the different dynamic settings for scripting, either
* ONLY_DISK_ALLOWED (scripts must be placed on disk), EVERYTHING_ALLOWED
@ -101,6 +127,96 @@ public class ScriptService extends AbstractComponent {
}
}
public static final ParseField SCRIPT_LANG = new ParseField("lang","script_lang");
public static final ParseField VALUE_SCRIPT_FILE = new ParseField("value_script_file");
public static final ParseField VALUE_SCRIPT_ID = new ParseField("value_script_id");
public static final ParseField VALUE_SCRIPT_INLINE = new ParseField("value_script");
public static final ParseField KEY_SCRIPT_FILE = new ParseField("key_script_file");
public static final ParseField KEY_SCRIPT_ID = new ParseField("key_script_id");
public static final ParseField KEY_SCRIPT_INLINE = new ParseField("key_script");
public static final ParseField SCRIPT_FILE = new ParseField("script_file","file");
public static final ParseField SCRIPT_ID = new ParseField("script_id", "id");
public static final ParseField SCRIPT_INLINE = new ParseField("script","scriptField");
private static final int INLINE_VAL = 0;
private static final int INDEXED_VAL = 1;
private static final int FILE_VAL = 2;
public static enum ScriptType {
INLINE(INLINE_VAL),
INDEXED(INDEXED_VAL),
FILE(FILE_VAL);
private int value;
private ScriptType(int i) {
this.value = i;
}
public static ScriptType readFrom(StreamInput in) throws IOException {
int scriptTypeVal = in.readVInt();
switch (scriptTypeVal) {
case INDEXED_VAL:
return INDEXED;
case INLINE_VAL:
return INLINE;
case FILE_VAL:
return FILE;
}
throw new ElasticsearchIllegalArgumentException("Unexpected value read for ScriptType got [" + scriptTypeVal +
"] expected one of ["+INLINE_VAL +"," + INDEXED_VAL + "," + FILE_VAL+"]");
}
public static void writeTo(ScriptType scriptType, StreamOutput out) throws IOException{
if (scriptType != null) {
switch (scriptType){
case INDEXED:
out.writeVInt(INDEXED_VAL);
return;
case INLINE:
out.writeVInt(INLINE_VAL);
return;
case FILE:
out.writeVInt(FILE_VAL);
return;
}
} else {
out.writeVInt(INLINE_VAL); //Default to inline
}
}
}
static class IndexedScript {
String lang;
String id;
IndexedScript(String lang, String script) {
this.lang = lang;
final String[] parts = script.split("/");
if (parts.length == 1) {
this.id = script;
if (this.lang == null){
this.lang = defaultLang;
}
} else {
if (parts.length != 3) {
throw new ElasticsearchIllegalArgumentException("Illegal index script format [" + script + "]" +
" should be /lang/id");
} else {
if (!parts[1].equals(this.lang)) {
throw new ElasticsearchIllegalStateException("Conflicting script language, found [" + parts[1] + "] expected + ["+ this.lang + "]");
}
this.id = parts[2];
}
}
}
}
@Inject
public ScriptService(Settings settings, Environment env, Set<ScriptEngineService> scriptEngines,
ResourceWatcherService resourceWatcherService) {
@ -135,6 +251,9 @@ public class ScriptService extends AbstractComponent {
// add file watcher for static scripts
scriptsDirectory = new File(env.configFile(), "scripts");
if (logger.isTraceEnabled()) {
logger.trace("Using scripts directory [{}] ", scriptsDirectory);
}
FileWatcher fileWatcher = new FileWatcher(scriptsDirectory);
fileWatcher.addListener(new ScriptChangesListener());
@ -147,6 +266,12 @@ public class ScriptService extends AbstractComponent {
}
}
//This isn't set in the ctor because doing so creates a guice circular
@Inject(optional=true)
public void setClient(Client client) {
this.client = client;
}
public void close() {
for (ScriptEngineService engineService : scriptEngines.values()) {
engineService.close();
@ -158,33 +283,227 @@ public class ScriptService extends AbstractComponent {
}
public CompiledScript compile(String lang, String script) {
CompiledScript compiled = staticCache.get(script);
if (compiled != null) {
return compiled;
return compile(lang, script, ScriptType.INLINE);
}
public CompiledScript compile(String lang, String script, ScriptType scriptType) {
if (logger.isTraceEnabled()) {
logger.trace("Compiling lang: [{}] type: [{}] script: {}", lang, scriptType, script);
}
CacheKey cacheKey;
CompiledScript compiled;
if(scriptType == ScriptType.INDEXED) {
if (client == null) {
throw new ElasticsearchIllegalArgumentException("Got an indexed script with no Client registered.");
}
final IndexedScript indexedScript = new IndexedScript(lang,script);
if (lang != null && !lang.equals(indexedScript.lang)) {
logger.trace("Overriding lang to " + indexedScript.lang);
lang = indexedScript.lang;
}
verifyDynamicScripting(indexedScript.lang); //Since anyone can index a script, disable indexed scripting
// if dynamic scripting is disabled, perhaps its own setting ?
script = getScriptFromIndex(client, indexedScript.lang, indexedScript.id);
} else if (scriptType == ScriptType.FILE) {
compiled = staticCache.get(script); //On disk scripts will be loaded into the staticCache by the listener
if (compiled != null) {
return compiled;
} else {
throw new ElasticsearchIllegalArgumentException("Unable to find on disk script " + script);
}
}
if (scriptType != ScriptType.INDEXED) {
//For backwards compat attempt to load from disk
compiled = staticCache.get(script); //On disk scripts will be loaded into the staticCache by the listener
if (compiled != null) {
return compiled;
}
}
if (lang == null) {
lang = defaultLang;
}
if (!dynamicScriptEnabled(lang)) {
throw new ScriptException("dynamic scripting for [" + lang + "] disabled");
}
CacheKey cacheKey = new CacheKey(lang, script);
//This is an inline script check to see if we have it in the cache
verifyDynamicScripting(lang);
cacheKey = new CacheKey(lang, script);
compiled = cache.getIfPresent(cacheKey);
if (compiled != null) {
return compiled;
}
// not the end of the world if we compile it twice...
ScriptEngineService service = scriptEngines.get(lang);
if (service == null) {
throw new ElasticsearchIllegalArgumentException("script_lang not supported [" + lang + "]");
//Either an un-cached inline script or an indexed script
if (!dynamicScriptEnabled(lang)) {
throw new ScriptException("dynamic scripting for [" + lang + "] disabled");
}
compiled = new CompiledScript(lang, service.compile(script));
if (cacheKey == null) {
cacheKey = new CacheKey(lang, script);
}
// not the end of the world if we compile it twice...
compiled = getCompiledScript(lang, script);
//Since the cache key is the script content itself we don't need to
//invalidate/check the cache if an indexed script changes.
cache.put(cacheKey, compiled);
return compiled;
}
public ExecutableScript executable(String lang, String script, Map vars) {
return executable(compile(lang, script), vars);
private CompiledScript getCompiledScript(String lang, String script) {
CompiledScript compiled;ScriptEngineService service = scriptEngines.get(lang);
if (service == null) {
throw new ElasticsearchIllegalArgumentException("script_lang not supported [" + lang + "]");
}
compiled = new CompiledScript(lang, service.compile(script));
return compiled;
}
private void verifyDynamicScripting(String lang) {
if (!dynamicScriptEnabled(lang)) {
throw new ScriptException("dynamic scripting for [" + lang + "] disabled");
}
}
public GetResponse queryScriptIndex(Client client, String scriptLang, String id){
return queryScriptIndex(client, scriptLang, id, Versions.MATCH_ANY, VersionType.INTERNAL);
}
public GetResponse queryScriptIndex(Client client, String scriptLang, String id,
long version, VersionType versionType){
scriptLang = validateScriptLanguage(scriptLang);
return client.prepareGet(SCRIPT_INDEX, scriptLang, id)
.setVersion(version)
.setVersionType(versionType)
.get();
}
private String validateScriptLanguage(String scriptLang) {
if (scriptLang == null){
scriptLang = defaultLang;
} else if (!scriptEngines.containsKey(scriptLang)){
throw new ElasticsearchIllegalArgumentException("script_lang not supported ["+scriptLang+"]");
}
return scriptLang;
}
private String getScriptFromIndex(Client client, String scriptLang, String id) {
GetResponse responseFields = queryScriptIndex(client,scriptLang,id);
if (responseFields.isExists()) {
return getScriptFromResponse(responseFields);
}
throw new ElasticsearchIllegalArgumentException("Unable to find script [" + SCRIPT_INDEX + "/"
+ scriptLang + "/" + id + "]");
}
private void validate(BytesReference scriptBytes, String scriptLang) throws IOException{
XContentParser parser = XContentFactory.xContent(scriptBytes).createParser(scriptBytes);
TemplateQueryParser.TemplateContext context = TemplateQueryParser.parse(parser, "params", "script", "template");
if (Strings.hasLength(context.template()) == true){
//Just try and compile it
//This will have the benefit of also adding the script to the cache if it compiles
try {
CompiledScript compiledScript = compile(scriptLang, context.template(), ScriptService.ScriptType.INLINE);
if (compiledScript == null) {
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + context.template() +
"] lang [" + scriptLang + "] (ScriptService.compile returned null)");
}
} catch (Exception e) {
throw new ElasticsearchIllegalArgumentException("Unable to parse [" + context.template() +
"] lang [" + scriptLang + "]", e);
}
} else {
throw new ElasticsearchIllegalArgumentException("Unable to find script in : " + scriptBytes.toUtf8());
}
}
public void putScriptToIndex(Client client, BytesReference scriptBytes, @Nullable String scriptLang, String id,
@Nullable TimeValue timeout, @Nullable String sOpType, ActionListener<IndexResponse> listener)
throws ElasticsearchIllegalArgumentException, IOException {
putScriptToIndex(client,scriptBytes,scriptLang,id,timeout,sOpType, Versions.MATCH_ANY, VersionType.INTERNAL, listener);
}
public void putScriptToIndex(Client client, BytesReference scriptBytes, @Nullable String scriptLang, String id,
@Nullable TimeValue timeout, @Nullable String sOpType, long version,
VersionType versionType, ActionListener<IndexResponse> listener) {
try {
scriptLang = validateScriptLanguage(scriptLang);
//verify that the script compiles
validate(scriptBytes, scriptLang);
IndexRequest indexRequest = new IndexRequest(SCRIPT_INDEX, scriptLang, id);
indexRequest.listenerThreaded(false);
indexRequest.operationThreaded(false);
indexRequest.version(version);
indexRequest.versionType(versionType);
indexRequest.refresh(true); //Always refresh after indexing a template
indexRequest.source(scriptBytes, true);
if (timeout != null) {
indexRequest.timeout(timeout);
}
if (sOpType != null) {
indexRequest.opType(IndexRequest.OpType.fromString(sOpType));
}
client.index(indexRequest, listener);
} catch (Throwable t){
listener.onFailure(t);
}
}
public void deleteScriptFromIndex(Client client, @Nullable String scriptLang, String id,
long version, ActionListener<DeleteResponse> listener) {
scriptLang = validateScriptLanguage(scriptLang);
client.delete((new DeleteRequest(SCRIPT_INDEX,scriptLang,id)).refresh(true).version(version), listener);
}
public static String getScriptFromResponse(GetResponse responseFields) {
Map<String, Object> source = responseFields.getSourceAsMap();
if (source.containsKey("template")) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
Object template = source.get("template");
if (template instanceof Map ){
builder.map((Map<String, Object>)template);
return builder.string();
} else {
return template.toString();
}
} catch (IOException | ClassCastException e) {
throw new ElasticsearchIllegalStateException("Unable to parse " + responseFields.getSourceAsString() + " as json", e);
}
} else if (source.containsKey("script")) {
return source.get("script").toString();
} else {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(responseFields.getSource());
return builder.string();
} catch (IOException|ClassCastException e) {
throw new ElasticsearchIllegalStateException("Unable to parse " + responseFields.getSourceAsString() + " as json", e);
}
}
}
public ExecutableScript executable(String lang, String script, ScriptType scriptType, Map vars) {
return executable(compile(lang, script, scriptType), vars);
}
public ExecutableScript executable(CompiledScript compiledScript, Map vars) {
@ -195,11 +514,11 @@ public class ScriptService extends AbstractComponent {
return scriptEngines.get(compiledScript.lang()).search(compiledScript.compiled(), lookup, vars);
}
public SearchScript search(SearchLookup lookup, String lang, String script, @Nullable Map<String, Object> vars) {
return search(compile(lang, script), lookup, vars);
public SearchScript search(SearchLookup lookup, String lang, String script, ScriptType scriptType, @Nullable Map<String, Object> vars) {
return search(compile(lang, script, scriptType), lookup, vars);
}
public SearchScript search(MapperService mapperService, IndexFieldDataService fieldDataService, String lang, String script, @Nullable Map<String, Object> vars) {
public SearchScript search(MapperService mapperService, IndexFieldDataService fieldDataService, String lang, String script, ScriptType scriptType, @Nullable Map<String, Object> vars) {
return search(compile(lang, script), new SearchLookup(mapperService, fieldDataService, null), vars);
}
@ -244,6 +563,9 @@ public class ScriptService extends AbstractComponent {
@Override
public void onFileInit(File file) {
if (logger.isTraceEnabled()) {
logger.trace("Loading script file : [{}]", file);
}
Tuple<String, String> scriptNameExt = scriptNameExt(file);
if (scriptNameExt != null) {
boolean found = false;
@ -294,6 +616,10 @@ public class ScriptService extends AbstractComponent {
public final String lang;
public final String script;
private CacheKey(){
throw new ElasticsearchIllegalStateException("CacheKey default constructor should never be called.");
}
public CacheKey(String lang, String script) {
this.lang = lang;
this.script = script;

View File

@ -48,11 +48,13 @@ public interface SearchScript extends ExecutableScript, ReaderContextAware, Scor
public static class Builder {
private String script;
private ScriptService.ScriptType scriptType;
private String lang;
private Map<String, Object> params;
public Builder script(String script) {
public Builder script(String script, ScriptService.ScriptType scriptType) {
this.script = script;
this.scriptType = scriptType;
return this;
}
@ -71,7 +73,7 @@ public interface SearchScript extends ExecutableScript, ReaderContextAware, Scor
}
public SearchScript build(ScriptService service, SearchLookup lookup) {
return service.search(lookup, lang, script, params);
return service.search(lookup, lang, script, scriptType, params);
}
}
}

View File

@ -79,6 +79,7 @@ import org.elasticsearch.search.warmer.IndexWarmersMetaData;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -583,33 +584,44 @@ public class SearchService extends AbstractLifecycleComponent<SearchService> {
}
private void parseTemplate(ShardSearchRequest request) {
final ExecutableScript executable;
if (hasLength(request.templateName())) {
ExecutableScript executable = this.scriptService.executable("mustache", request.templateName(), request.templateParams());
BytesReference processedQuery = (BytesReference) executable.run();
request.source(processedQuery);
executable = this.scriptService.executable("mustache", request.templateName(), request.templateType(), request.templateParams());
} else {
if (request.templateSource() == null || request.templateSource().length() == 0) {
if (!hasLength(request.templateSource())) {
return;
}
XContentParser parser = null;
TemplateQueryParser.TemplateContext templateContext = null;
try {
parser = XContentFactory.xContent(request.templateSource()).createParser(request.templateSource());
templateContext = TemplateQueryParser.parse(parser, "params", "template");
TemplateQueryParser.TemplateContext templateContext = TemplateQueryParser.parse(parser, "template", "params");
if (!hasLength(templateContext.template())) {
throw new ElasticsearchParseException("Template must have [template] field configured");
if (templateContext.scriptType().equals(ScriptService.ScriptType.INLINE)) {
//Try to double parse for nested template id/file
parser = XContentFactory.xContent(templateContext.template().getBytes(Charset.defaultCharset())).createParser(templateContext.template().getBytes(Charset.defaultCharset()));
TemplateQueryParser.TemplateContext innerContext = TemplateQueryParser.parse(parser, "params");
if (hasLength(innerContext.template()) && !innerContext.scriptType().equals(ScriptService.ScriptType.INLINE)) {
//An inner template referring to a filename or id
templateContext = new TemplateQueryParser.TemplateContext(innerContext.scriptType(), innerContext.template(), templateContext.params());
}
}
ExecutableScript executable = this.scriptService.executable("mustache", templateContext.template(), templateContext.params());
BytesReference processedQuery = (BytesReference) executable.run();
request.source(processedQuery);
} catch (IOException e) {
logger.error("Error trying to parse template: ", e);
throw new ElasticsearchParseException("Failed to parse template", e);
} finally {
IOUtils.closeWhileHandlingException(parser);
}
if (templateContext == null || !hasLength(templateContext.template())) {
throw new ElasticsearchParseException("Template must have [template] field configured");
}
executable = this.scriptService.executable("mustache", templateContext.template(), templateContext.scriptType(), templateContext.params());
}
BytesReference processedQuery = (BytesReference) executable.run();
request.source(processedQuery);
}
private void parseSource(SearchContext context, BytesReference source) throws SearchParseException {

View File

@ -28,6 +28,7 @@ import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.core.DateFieldMapper;
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.InternalAggregation;
@ -61,6 +62,7 @@ public class ValuesSourceParser<VS extends ValuesSource> {
private static class Input {
String field = null;
String script = null;
ScriptService.ScriptType scriptType = null;
String lang = null;
Map<String, Object> params = null;
ValueType valueType = null;
@ -98,6 +100,13 @@ public class ValuesSourceParser<VS extends ValuesSource> {
} else if (scriptable) {
if ("script".equals(currentFieldName)) {
input.script = parser.text();
input.scriptType = ScriptService.ScriptType.INLINE;
} else if ("script_id".equals(currentFieldName)) {
input.script = parser.text();
input.scriptType = ScriptService.ScriptType.INDEXED;
} else if ("script_file".equals(currentFieldName)) {
input.script = parser.text();
input.scriptType = ScriptService.ScriptType.FILE;
} else if ("lang".equals(currentFieldName)) {
input.lang = parser.text();
} else if ("value_type".equals(currentFieldName) || "valueType".equals(currentFieldName)) {
@ -199,7 +208,7 @@ public class ValuesSourceParser<VS extends ValuesSource> {
}
private SearchScript createScript() {
return input.script == null ? null : context.scriptService().search(context.lookup(), input.lang, input.script, input.params);
return input.script == null ? null : context.scriptService().search(context.lookup(), input.lang, input.script, input.scriptType, input.params);
}
private static ValueFormat resolveFormat(@Nullable String format, @Nullable ValueType valueType) {

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
@ -94,6 +95,7 @@ public class DateHistogramFacetParser extends AbstractComponent implements Facet
String keyField = null;
String valueField = null;
String valueScript = null;
ScriptService.ScriptType valueScriptType = null;
String scriptLang = null;
Map<String, Object> params = null;
String interval = null;
@ -137,11 +139,18 @@ public class DateHistogramFacetParser extends AbstractComponent implements Facet
postOffset = parseOffset(parser.text());
} else if ("factor".equals(fieldName)) {
factor = parser.floatValue();
} else if ("value_script".equals(fieldName) || "valueScript".equals(fieldName)) {
} else if (ScriptService.VALUE_SCRIPT_INLINE.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.VALUE_SCRIPT_ID.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.VALUE_SCRIPT_FILE.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.FILE;
} else if ("order".equals(fieldName) || "comparator".equals(fieldName)) {
comparatorType = DateHistogramFacet.ComparatorType.fromString(parser.text());
} else if ("lang".equals(fieldName)) {
} else if (ScriptService.SCRIPT_LANG.match(fieldName)) {
scriptLang = parser.text();
}
}
@ -178,7 +187,7 @@ public class DateHistogramFacetParser extends AbstractComponent implements Facet
.build();
if (valueScript != null) {
SearchScript script = context.scriptService().search(context.lookup(), scriptLang, valueScript, params);
SearchScript script = context.scriptService().search(context.lookup(), scriptLang, valueScript, valueScriptType, params);
return new ValueScriptDateHistogramFacetExecutor(keyIndexFieldData, script, tzRounding, comparatorType, context.cacheRecycler());
} else if (valueField != null) {
FieldMapper valueMapper = context.smartNameFieldMapper(valueField);

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
import org.elasticsearch.search.facet.FacetPhaseExecutionException;
@ -70,6 +71,7 @@ public class GeoDistanceFacetParser extends AbstractComponent implements FacetPa
String fieldName = null;
String valueFieldName = null;
String valueScript = null;
ScriptService.ScriptType scriptType = null;
String scriptLang = null;
Map<String, Object> params = null;
GeoPoint point = new GeoPoint();
@ -127,9 +129,16 @@ public class GeoDistanceFacetParser extends AbstractComponent implements FacetPa
geoDistance = GeoDistance.fromString(parser.text());
} else if ("value_field".equals(currentName) || "valueField".equals(currentName)) {
valueFieldName = parser.text();
} else if ("value_script".equals(currentName) || "valueScript".equals(currentName)) {
} else if (ScriptService.VALUE_SCRIPT_INLINE.match(currentName)) {
valueScript = parser.text();
} else if ("lang".equals(currentName)) {
scriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.VALUE_SCRIPT_ID.match(currentName)) {
valueScript = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.VALUE_SCRIPT_FILE.match(currentName)) {
valueScript = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(currentName)) {
scriptLang = parser.text();
} else if ("normalize".equals(currentName)) {
normalizeLat = parser.booleanValue();
@ -169,7 +178,7 @@ public class GeoDistanceFacetParser extends AbstractComponent implements FacetPa
if (valueScript != null) {
return new ScriptGeoDistanceFacetExecutor(keyIndexFieldData, point.lat(), point.lon(), unit, geoDistance, entries.toArray(new GeoDistanceFacet.Entry[entries.size()]),
context, scriptLang, valueScript, params);
context, scriptLang, valueScript, scriptType, params);
}
return new GeoDistanceFacetExecutor(keyIndexFieldData, point.lat(), point.lon(), unit, geoDistance, entries.toArray(new GeoDistanceFacet.Entry[entries.size()]),

View File

@ -27,6 +27,7 @@ import org.apache.lucene.search.Scorer;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.internal.SearchContext;
@ -39,9 +40,9 @@ public class ScriptGeoDistanceFacetExecutor extends GeoDistanceFacetExecutor {
public ScriptGeoDistanceFacetExecutor(IndexGeoPointFieldData indexFieldData, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance,
GeoDistanceFacet.Entry[] entries, SearchContext context,
String scriptLang, String script, Map<String, Object> params) {
String scriptLang, String script, ScriptService.ScriptType scriptType, Map<String, Object> params) {
super(indexFieldData, lat, lon, unit, geoDistance, entries, context);
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
this.script = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
}
@Override

View File

@ -25,6 +25,7 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
import org.elasticsearch.search.facet.FacetPhaseExecutionException;
@ -71,6 +72,8 @@ public class HistogramFacetParser extends AbstractComponent implements FacetPars
HistogramFacet.ComparatorType comparatorType = HistogramFacet.ComparatorType.KEY;
XContentParser.Token token;
String fieldName = null;
ScriptService.ScriptType valueScriptType = null;
ScriptService.ScriptType keyScriptType = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
fieldName = parser.currentName();
@ -89,20 +92,34 @@ public class HistogramFacetParser extends AbstractComponent implements FacetPars
interval = parser.longValue();
} else if ("time_interval".equals(fieldName) || "timeInterval".equals(fieldName)) {
interval = TimeValue.parseTimeValue(parser.text(), null).millis();
} else if ("key_script".equals(fieldName) || "keyScript".equals(fieldName)) {
keyScript = parser.text();
} else if ("value_script".equals(fieldName) || "valueScript".equals(fieldName)) {
valueScript = parser.text();
} else if ("order".equals(fieldName) || "comparator".equals(fieldName)) {
comparatorType = HistogramFacet.ComparatorType.fromString(parser.text());
} else if ("lang".equals(fieldName)) {
} else if (ScriptService.KEY_SCRIPT_INLINE.match(fieldName)) {
keyScript = parser.text();
keyScriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.KEY_SCRIPT_ID.match(fieldName)) {
keyScript = parser.text();
keyScriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.KEY_SCRIPT_FILE.match(fieldName)) {
keyScript = parser.text();
keyScriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.VALUE_SCRIPT_INLINE.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.VALUE_SCRIPT_ID.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.VALUE_SCRIPT_FILE.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(fieldName)) {
scriptLang = parser.text();
}
}
}
if (keyScript != null && valueScript != null) {
return new ScriptHistogramFacetExecutor(scriptLang, keyScript, valueScript, params, interval, comparatorType, context);
return new ScriptHistogramFacetExecutor(scriptLang, keyScript, keyScriptType, valueScript, valueScriptType, params, interval, comparatorType, context);
}
if (keyField == null) {
@ -129,7 +146,7 @@ public class HistogramFacetParser extends AbstractComponent implements FacetPars
}
if (valueScript != null) {
return new ValueScriptHistogramFacetExecutor(keyIndexFieldData, scriptLang, valueScript, params, interval, comparatorType, context);
return new ValueScriptHistogramFacetExecutor(keyIndexFieldData, scriptLang, valueScript, valueScriptType, params, interval, comparatorType, context);
} else if (valueField == null) {
return new CountHistogramFacetExecutor(keyIndexFieldData, interval, comparatorType, context);
} else if (keyField.equals(valueField)) {

View File

@ -23,6 +23,7 @@ import com.carrotsearch.hppc.LongObjectOpenHashMap;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.common.recycler.Recycler;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.InternalFacet;
@ -45,9 +46,9 @@ public class ScriptHistogramFacetExecutor extends FacetExecutor {
final Recycler.V<LongObjectOpenHashMap<InternalFullHistogramFacet.FullEntry>> entries;
public ScriptHistogramFacetExecutor(String scriptLang, String keyScript, String valueScript, Map<String, Object> params, long interval, HistogramFacet.ComparatorType comparatorType, SearchContext context) {
this.keyScript = context.scriptService().search(context.lookup(), scriptLang, keyScript, params);
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, params);
public ScriptHistogramFacetExecutor(String scriptLang, String keyScript, ScriptService.ScriptType keyScriptType, String valueScript, ScriptService.ScriptType valueScriptType, Map<String, Object> params, long interval, HistogramFacet.ComparatorType comparatorType, SearchContext context) {
this.keyScript = context.scriptService().search(context.lookup(), scriptLang, keyScript, keyScriptType, params);
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, valueScriptType, params);
this.interval = interval > 0 ? interval : 0;
this.comparatorType = comparatorType;

View File

@ -25,6 +25,7 @@ import org.apache.lucene.search.Scorer;
import org.elasticsearch.common.recycler.Recycler;
import org.elasticsearch.index.fielddata.DoubleValues;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.DoubleFacetAggregatorBase;
import org.elasticsearch.search.facet.FacetExecutor;
@ -46,14 +47,13 @@ public class ValueScriptHistogramFacetExecutor extends FacetExecutor {
private final HistogramFacet.ComparatorType comparatorType;
final SearchScript valueScript;
final long interval;
final Recycler.V<LongObjectOpenHashMap<InternalFullHistogramFacet.FullEntry>> entries;
public ValueScriptHistogramFacetExecutor(IndexNumericFieldData indexFieldData, String scriptLang, String valueScript, Map<String, Object> params, long interval, HistogramFacet.ComparatorType comparatorType, SearchContext context) {
public ValueScriptHistogramFacetExecutor(IndexNumericFieldData indexFieldData, String scriptLang, String valueScript, ScriptService.ScriptType scriptType, Map<String, Object> params, long interval, HistogramFacet.ComparatorType comparatorType, SearchContext context) {
this.comparatorType = comparatorType;
this.indexFieldData = indexFieldData;
this.interval = interval;
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, params);
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, scriptType, params);
this.entries = context.cacheRecycler().longObjectMap(-1);
}

View File

@ -25,6 +25,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
import org.elasticsearch.search.facet.FacetPhaseExecutionException;
@ -66,7 +67,9 @@ public class RangeFacetParser extends AbstractComponent implements FacetParser {
String valueField = null;
String scriptLang = null;
String keyScript = null;
ScriptService.ScriptType keyScriptType = null;
String valueScript = null;
ScriptService.ScriptType valueScriptType = null;
Map<String, Object> params = null;
XContentParser.Token token;
String fieldName = null;
@ -112,11 +115,25 @@ public class RangeFacetParser extends AbstractComponent implements FacetParser {
keyField = parser.text();
} else if ("value_field".equals(fieldName) || "valueField".equals(fieldName)) {
valueField = parser.text();
} else if ("key_script".equals(fieldName) || "keyScript".equals(fieldName)) {
} else if (ScriptService.KEY_SCRIPT_INLINE.match(fieldName)) {
keyScript = parser.text();
} else if ("value_script".equals(fieldName) || "valueScript".equals(fieldName)) {
keyScriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.KEY_SCRIPT_ID.match(fieldName)) {
keyScript = parser.text();
keyScriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.KEY_SCRIPT_FILE.match(fieldName)) {
keyScript = parser.text();
keyScriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.VALUE_SCRIPT_INLINE.match(fieldName)) {
valueScript = parser.text();
} else if ("lang".equals(fieldName)) {
valueScriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.VALUE_SCRIPT_ID.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.VALUE_SCRIPT_FILE.match(fieldName)) {
valueScript = parser.text();
valueScriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(fieldName)) {
scriptLang = parser.text();
}
}
@ -129,7 +146,7 @@ public class RangeFacetParser extends AbstractComponent implements FacetParser {
RangeFacet.Entry[] rangeEntries = entries.toArray(new RangeFacet.Entry[entries.size()]);
if (keyScript != null && valueScript != null) {
return new ScriptRangeFacetExecutor(scriptLang, keyScript, valueScript, params, rangeEntries, context);
return new ScriptRangeFacetExecutor(scriptLang, keyScript, keyScriptType, valueScript, valueScriptType, params, rangeEntries, context);
}
if (keyField == null) {

View File

@ -21,6 +21,7 @@ package org.elasticsearch.search.facet.range;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.InternalFacet;
@ -39,9 +40,9 @@ public class ScriptRangeFacetExecutor extends FacetExecutor {
private final RangeFacet.Entry[] entries;
public ScriptRangeFacetExecutor(String scriptLang, String keyScript, String valueScript, Map<String, Object> params, RangeFacet.Entry[] entries, SearchContext context) {
this.keyScript = context.scriptService().search(context.lookup(), scriptLang, keyScript, params);
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, params);
public ScriptRangeFacetExecutor(String scriptLang, String keyScript, ScriptService.ScriptType keyScriptType, String valueScript, ScriptService.ScriptType valueScriptType, Map<String, Object> params, RangeFacet.Entry[] entries, SearchContext context) {
this.keyScript = context.scriptService().search(context.lookup(), scriptLang, keyScript, keyScriptType, params);
this.valueScript = context.scriptService().search(context.lookup(), scriptLang, valueScript, valueScriptType, params);
this.entries = entries;
}

View File

@ -21,6 +21,7 @@ package org.elasticsearch.search.facet.statistical;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Scorer;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.InternalFacet;
@ -42,8 +43,8 @@ public class ScriptStatisticalFacetExecutor extends FacetExecutor {
private double sumOfSquares = 0.0;
private long count;
public ScriptStatisticalFacetExecutor(String scriptLang, String script, Map<String, Object> params, SearchContext context) {
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
public ScriptStatisticalFacetExecutor(String scriptLang, String script, ScriptService.ScriptType scriptType, Map<String, Object> params, SearchContext context) {
this.script = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
}
@Override

View File

@ -26,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
import org.elasticsearch.search.facet.FacetPhaseExecutionException;
@ -68,6 +69,7 @@ public class StatisticalFacetParser extends AbstractComponent implements FacetPa
String script = null;
String scriptLang = null;
ScriptService.ScriptType scriptType = null;
Map<String, Object> params = null;
String currentFieldName = null;
@ -92,6 +94,13 @@ public class StatisticalFacetParser extends AbstractComponent implements FacetPa
field = parser.text();
} else if ("script".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if ("id".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if ("file".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
}
@ -125,7 +134,7 @@ public class StatisticalFacetParser extends AbstractComponent implements FacetPa
IndexNumericFieldData indexFieldData = context.fieldData().getForField(fieldMapper);
return new StatisticalFacetExecutor(indexFieldData, context);
} else {
return new ScriptStatisticalFacetExecutor(scriptLang, script, params, context);
return new ScriptStatisticalFacetExecutor(scriptLang, script, scriptType, params, context);
}
}
}

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
@ -90,6 +91,7 @@ public class TermsFacetParser extends AbstractComponent implements FacetParser {
TermsFacet.ComparatorType comparatorType = TermsFacet.ComparatorType.COUNT;
String scriptLang = null;
String script = null;
ScriptService.ScriptType scriptType = null;
Map<String, Object> params = null;
boolean allTerms = false;
String executionHint = null;
@ -124,8 +126,17 @@ public class TermsFacetParser extends AbstractComponent implements FacetParser {
} else if (token.isValue()) {
if ("field".equals(currentFieldName)) {
field = parser.text();
} else if ("script_field".equals(currentFieldName) || "scriptField".equals(currentFieldName)) {
} else if (ScriptService.SCRIPT_INLINE.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.SCRIPT_ID.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.SCRIPT_FILE.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(currentFieldName)) {
scriptLang = parser.text();
} else if ("size".equals(currentFieldName)) {
size = parser.intValue();
} else if ("shard_size".equals(currentFieldName) || "shardSize".equals(currentFieldName)) {
@ -138,10 +149,6 @@ public class TermsFacetParser extends AbstractComponent implements FacetParser {
regexFlags = parser.text();
} else if ("order".equals(currentFieldName) || "comparator".equals(currentFieldName)) {
comparatorType = TermsFacet.ComparatorType.fromString(parser.text());
} else if ("script".equals(currentFieldName)) {
script = parser.text();
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
} else if ("execution_hint".equals(currentFieldName) || "executionHint".equals(currentFieldName)) {
executionHint = parser.textOrNull();
} else {
@ -162,7 +169,7 @@ public class TermsFacetParser extends AbstractComponent implements FacetParser {
SearchScript searchScript = null;
if (script != null) {
searchScript = context.scriptService().search(context.lookup(), scriptLang, script, params);
searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
}
// shard_size cannot be smaller than size as we need to at least fetch <size> entries from every shards in order to return <size>
@ -187,7 +194,7 @@ public class TermsFacetParser extends AbstractComponent implements FacetParser {
return new FieldsTermsStringFacetExecutor(mappers.toArray(new FieldMapper[mappers.size()]), size, shardSize, comparatorType, allTerms, context, excluded, pattern, searchScript);
}
if (field == null && script != null) {
return new ScriptTermsStringFieldFacetExecutor(size, shardSize, comparatorType, context, excluded, pattern, scriptLang, script, params, context.cacheRecycler());
return new ScriptTermsStringFieldFacetExecutor(size, shardSize, comparatorType, context, excluded, pattern, scriptLang, script, scriptType, params, context.cacheRecycler());
}
if (field == null) {

View File

@ -28,6 +28,7 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.cache.recycler.CacheRecycler;
import org.elasticsearch.common.collect.BoundedTreeSet;
import org.elasticsearch.common.recycler.Recycler;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.InternalFacet;
@ -58,13 +59,13 @@ public class ScriptTermsStringFieldFacetExecutor extends FacetExecutor {
long total;
public ScriptTermsStringFieldFacetExecutor(int size, int shardSize, InternalStringTermsFacet.ComparatorType comparatorType, SearchContext context,
ImmutableSet<BytesRef> excluded, Pattern pattern, String scriptLang, String script, Map<String, Object> params,
ImmutableSet<BytesRef> excluded, Pattern pattern, String scriptLang, String script, ScriptService.ScriptType scriptType, Map<String, Object> params,
CacheRecycler cacheRecycler) {
this.size = size;
this.shardSize = shardSize;
this.comparatorType = comparatorType;
this.numberOfShards = context.numberOfShards();
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
this.script = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
this.excluded = excluded;
this.matcher = pattern != null ? pattern.matcher("") : null;

View File

@ -27,6 +27,7 @@ import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.core.NumberFieldMapper;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.facet.FacetExecutor;
import org.elasticsearch.search.facet.FacetParser;
@ -71,6 +72,7 @@ public class TermsStatsFacetParser extends AbstractComponent implements FacetPar
TermsStatsFacet.ComparatorType comparatorType = TermsStatsFacet.ComparatorType.COUNT;
String scriptLang = null;
String script = null;
ScriptService.ScriptType scriptType = null;
Map<String, Object> params = null;
String currentFieldName = null;
@ -85,12 +87,19 @@ public class TermsStatsFacetParser extends AbstractComponent implements FacetPar
} else if (token.isValue()) {
if ("key_field".equals(currentFieldName) || "keyField".equals(currentFieldName)) {
keyField = parser.text();
} else if (ScriptService.VALUE_SCRIPT_INLINE.match(currentFieldName) || ScriptService.SCRIPT_INLINE.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.VALUE_SCRIPT_ID.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.VALUE_SCRIPT_FILE.match(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(currentFieldName)) {
scriptLang = parser.text();
} else if ("value_field".equals(currentFieldName) || "valueField".equals(currentFieldName)) {
valueField = parser.text();
} else if ("script_field".equals(currentFieldName) || "scriptField".equals(currentFieldName)) {
script = parser.text();
} else if ("value_script".equals(currentFieldName) || "valueScript".equals(currentFieldName)) {
script = parser.text();
} else if ("size".equals(currentFieldName)) {
size = parser.intValue();
} else if ("shard_size".equals(currentFieldName) || "shardSize".equals(currentFieldName)) {
@ -101,8 +110,6 @@ public class TermsStatsFacetParser extends AbstractComponent implements FacetPar
}
} else if ("order".equals(currentFieldName) || "comparator".equals(currentFieldName)) {
comparatorType = TermsStatsFacet.ComparatorType.fromString(parser.text());
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
}
}
}
@ -135,7 +142,7 @@ public class TermsStatsFacetParser extends AbstractComponent implements FacetPar
}
valueIndexFieldData = context.fieldData().getForField(fieldMapper);
} else {
valueScript = context.scriptService().search(context.lookup(), scriptLang, script, params);
valueScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
}
if (keyIndexFieldData instanceof IndexNumericFieldData) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.search.fetch.script;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.internal.SearchContext;
@ -53,6 +54,7 @@ public class ScriptFieldsParseElement implements SearchParseElement {
String fieldName = currentFieldName;
String script = null;
String scriptLang = null;
ScriptService.ScriptType scriptType = null;
Map<String, Object> params = null;
boolean ignoreException = false;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
@ -63,6 +65,13 @@ public class ScriptFieldsParseElement implements SearchParseElement {
} else if (token.isValue()) {
if ("script".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if ("id".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if ("file".equals(currentFieldName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if ("lang".equals(currentFieldName)) {
scriptLang = parser.text();
} else if ("ignore_failure".equals(currentFieldName)) {
@ -70,7 +79,7 @@ public class ScriptFieldsParseElement implements SearchParseElement {
}
}
}
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, params);
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
context.scriptFields().add(new ScriptFieldsContext.ScriptField(fieldName, searchScript, ignoreException));
}
}

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.transport.TransportRequest;
@ -73,6 +74,7 @@ public class ShardSearchRequest extends TransportRequest {
private BytesReference extraSource;
private BytesReference templateSource;
private String templateName;
private ScriptService.ScriptType templateType;
private Map<String, String> templateParams;
private long nowInMillis;
@ -92,6 +94,7 @@ public class ShardSearchRequest extends TransportRequest {
this.extraSource = searchRequest.extraSource();
this.templateSource = searchRequest.templateSource();
this.templateName = searchRequest.templateName();
this.templateType = searchRequest.templateType();
this.templateParams = searchRequest.templateParams();
this.scroll = searchRequest.scroll();
this.types = searchRequest.types();
@ -151,6 +154,10 @@ public class ShardSearchRequest extends TransportRequest {
return templateName;
}
public ScriptService.ScriptType templateType() {
return templateType;
}
public Map<String, String> templateParams() {
return templateParams;
}
@ -223,6 +230,9 @@ public class ShardSearchRequest extends TransportRequest {
if (in.getVersion().onOrAfter(Version.V_1_1_0)) {
templateSource = in.readBytesReference();
templateName = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_1_3_0)) {
templateType = ScriptService.ScriptType.readFrom(in);
}
if (in.readBoolean()) {
templateParams = (Map<String, String>) in.readGenericValue();
}
@ -257,6 +267,9 @@ public class ShardSearchRequest extends TransportRequest {
if (out.getVersion().onOrAfter(Version.V_1_1_0)) {
out.writeBytesReference(templateSource);
out.writeOptionalString(templateName);
if (out.getVersion().onOrAfter(Version.V_1_3_0)) {
ScriptService.ScriptType.writeTo(templateType, out);
}
boolean existTemplateParams = templateParams != null;
out.writeBoolean(existTemplateParams);
if (existTemplateParams) {

View File

@ -32,6 +32,7 @@ import org.elasticsearch.index.mapper.object.ObjectMapper;
import org.elasticsearch.index.query.ParsedFilter;
import org.elasticsearch.index.search.nested.NestedFieldComparatorSource;
import org.elasticsearch.index.search.nested.NonNestedDocsFilter;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.internal.SearchContext;
@ -61,6 +62,7 @@ public class ScriptSortParser implements SortParser {
XContentParser.Token token;
String currentName = parser.currentName();
ScriptService.ScriptType scriptType = ScriptService.ScriptType.INLINE;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentName = parser.currentName();
@ -76,12 +78,19 @@ public class ScriptSortParser implements SortParser {
reverse = parser.booleanValue();
} else if ("order".equals(currentName)) {
reverse = "desc".equals(parser.text());
} else if ("script".equals(currentName)) {
} else if (ScriptService.SCRIPT_INLINE.match(currentName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INLINE;
} else if (ScriptService.SCRIPT_ID.match(currentName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.INDEXED;
} else if (ScriptService.SCRIPT_FILE.match(currentName)) {
script = parser.text();
scriptType = ScriptService.ScriptType.FILE;
} else if (ScriptService.SCRIPT_LANG.match(currentName)) {
scriptLang = parser.text();
} else if ("type".equals(currentName)) {
type = parser.text();
} else if ("lang".equals(currentName)) {
scriptLang = parser.text();
} else if ("mode".equals(currentName)) {
sortMode = MultiValueMode.fromString(parser.text());
} else if ("nested_path".equals(currentName) || "nestedPath".equals(currentName)) {
@ -96,7 +105,7 @@ public class ScriptSortParser implements SortParser {
if (type == null) {
throw new SearchParseException(context, "_script sorting requires setting the type of the script");
}
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, params);
SearchScript searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptType, params);
IndexFieldData.XFieldComparatorSource fieldComparatorSource;
if ("string".equals(type)) {
fieldComparatorSource = StringScriptDataComparator.comparatorSource(searchScript);

View File

@ -0,0 +1,48 @@
/*
* 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.index;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
/**
*/
public class IndexRequestTests extends ElasticsearchTestCase {
@Test
public void testIndexRequestOpTypeFromString() throws Exception {
String create = "create";
String index = "index";
String createUpper = "CREATE";
String indexUpper = "INDEX";
assertThat(IndexRequest.OpType.fromString(create), equalTo(IndexRequest.OpType.CREATE));
assertThat(IndexRequest.OpType.fromString(index), equalTo(IndexRequest.OpType.INDEX));
assertThat(IndexRequest.OpType.fromString(createUpper), equalTo(IndexRequest.OpType.CREATE));
assertThat(IndexRequest.OpType.fromString(indexUpper), equalTo(IndexRequest.OpType.INDEX));
}
@Test(expected= ElasticsearchIllegalArgumentException.class)
public void testReadBogusString(){
String foobar = "foobar";
IndexRequest.OpType.fromString(foobar);
}
}

View File

@ -98,7 +98,7 @@ public class NoMasterNodeTests extends ElasticsearchIntegrationTest {
long now = System.currentTimeMillis();
try {
client().prepareUpdate("test", "type1", "1").setScript("test script").setTimeout(timeout).execute().actionGet();
client().prepareUpdate("test", "type1", "1").setInlineScript("test script").setTimeout(timeout).execute().actionGet();
fail("Expected ClusterBlockException");
} catch (ClusterBlockException e) {
assertThat(System.currentTimeMillis() - now, greaterThan(timeout.millis() - 50));

View File

@ -65,8 +65,8 @@ public class BulkTests extends ElasticsearchIntegrationTest {
assertThat(bulkResponse.getItems().length, equalTo(5));
bulkResponse = client().prepareBulk()
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("1").setScript("ctx._source.field += 1"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setScript("ctx._source.field += 1").setRetryOnConflict(3))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("1").setInlineScript("ctx._source.field += 1"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setInlineScript("ctx._source.field += 1").setRetryOnConflict(3))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("3").setDoc(jsonBuilder().startObject().field("field1", "test").endObject()))
.execute().actionGet();
@ -95,10 +95,10 @@ public class BulkTests extends ElasticsearchIntegrationTest {
assertThat(getResponse.getField("field1").getValue().toString(), equalTo("test"));
bulkResponse = client().prepareBulk()
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("6").setScript("ctx._source.field += 1")
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("6").setInlineScript("ctx._source.field += 1")
.setUpsert(jsonBuilder().startObject().field("field", 0).endObject()))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("7").setScript("ctx._source.field += 1"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setScript("ctx._source.field += 1"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("7").setInlineScript("ctx._source.field += 1"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setInlineScript("ctx._source.field += 1"))
.execute().actionGet();
assertThat(bulkResponse.hasFailures(), equalTo(true));
@ -188,9 +188,9 @@ public class BulkTests extends ElasticsearchIntegrationTest {
assertThat(bulkResponse.getItems().length, equalTo(3));
bulkResponse = client().prepareBulk()
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("1").setScript("ctx._source.field += a").setFields("field"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setScript("ctx._source.field += 1").setFields("field"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("3").setScript("ctx._source.field += a").setFields("field"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("1").setInlineScript("ctx._source.field += a").setFields("field"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("2").setInlineScript("ctx._source.field += 1").setFields("field"))
.add(client().prepareUpdate().setIndex("test").setType("type1").setId("3").setInlineScript("ctx._source.field += a").setFields("field"))
.execute().actionGet();
assertThat(bulkResponse.hasFailures(), equalTo(true));
@ -224,7 +224,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
builder.add(
client().prepareUpdate()
.setIndex("test").setType("type1").setId(Integer.toString(i))
.setScript("ctx._source.counter += 1").setFields("counter")
.setInlineScript("ctx._source.counter += 1").setFields("counter")
.setUpsert(jsonBuilder().startObject().field("counter", 1).endObject())
);
}
@ -255,7 +255,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
UpdateRequestBuilder updateBuilder = client().prepareUpdate()
.setIndex("test").setType("type1").setId(Integer.toString(i)).setFields("counter");
if (i % 2 == 0) {
updateBuilder.setScript("ctx._source.counter += 1");
updateBuilder.setInlineScript("ctx._source.counter += 1");
} else {
updateBuilder.setDoc(jsonBuilder().startObject().field("counter", 2).endObject());
}
@ -285,7 +285,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
for (int i = (numDocs / 2); i < maxDocs; i++) {
builder.add(
client().prepareUpdate()
.setIndex("test").setType("type1").setId(Integer.toString(i)).setScript("ctx._source.counter += 1")
.setIndex("test").setType("type1").setId(Integer.toString(i)).setInlineScript("ctx._source.counter += 1")
);
}
response = builder.execute().actionGet();
@ -309,7 +309,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
for (int i = 0; i < numDocs; i++) {
builder.add(
client().prepareUpdate()
.setIndex("test").setType("type1").setId(Integer.toString(i)).setScript("ctx.op = \"none\"")
.setIndex("test").setType("type1").setId(Integer.toString(i)).setInlineScript("ctx.op = \"none\"")
);
}
response = builder.execute().actionGet();
@ -327,7 +327,7 @@ public class BulkTests extends ElasticsearchIntegrationTest {
for (int i = 0; i < numDocs; i++) {
builder.add(
client().prepareUpdate()
.setIndex("test").setType("type1").setId(Integer.toString(i)).setScript("ctx.op = \"delete\"")
.setIndex("test").setType("type1").setId(Integer.toString(i)).setInlineScript("ctx.op = \"delete\"")
);
}
response = builder.execute().actionGet();

View File

@ -114,7 +114,7 @@ public class TemplateQueryParserTest extends ElasticsearchTestCase {
@Test
public void testParserCanExtractTemplateNames() throws Exception {
String templateString = "{ \"template\": { \"query\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } } ";
String templateString = "{ \"template\": { \"file\": \"storedTemplate\" ,\"params\":{\"template\":\"all\" } } } ";
XContentParser templateSourceParser = XContentFactory.xContent(templateString).createParser(templateString);
context.reset(templateSourceParser);

View File

@ -19,23 +19,32 @@
package org.elasticsearch.index.query;
import com.google.common.collect.Maps;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.get.GetIndexedScriptResponse;
import org.elasticsearch.action.indexedscripts.put.PutIndexedScriptResponse;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@ -125,7 +134,7 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest {
vars.put("template", "all");
TemplateQueryBuilder builder = new TemplateQueryBuilder(
"storedTemplate", vars);
"storedTemplate", ScriptService.ScriptType.FILE, vars);
SearchResponse sr = client().prepareSearch().setQuery(builder)
.execute().actionGet();
assertHitCount(sr, 2);
@ -149,7 +158,7 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest {
@Test
public void testRawFSTemplate() throws IOException {
String query = "{\"template\": {\"query\": \"storedTemplate\",\"params\" : {\"template\" : \"all\"}}}";
String query = "{\"template\": {\"file\": \"storedTemplate\",\"params\" : {\"template\" : \"all\"}}}";
SearchResponse sr = client().prepareSearch().setQuery(query).get();
assertHitCount(sr, 2);
@ -213,4 +222,167 @@ public class TemplateQueryTest extends ElasticsearchIntegrationTest {
searchResponse = client().prepareSearch("test").setTypes("type").setTemplateName("full-query-template").setTemplateParams(templateParams).get();
assertHitCount(searchResponse, 1);
}
@Test
public void testIndexedTemplateClient() throws Exception {
createIndex(ScriptService.SCRIPT_INDEX);
ensureGreen(ScriptService.SCRIPT_INDEX);
PutIndexedScriptResponse scriptResponse = client().preparePutIndexedScript("mustache", "testTemplate", "{" +
"\"template\":{" +
" \"query\":{" +
" \"match\":{" +
" \"theField\" : \"{{fieldParam}}\"}" +
" }" +
"}" +
"}").get();
assertTrue(scriptResponse.isCreated());
scriptResponse = client().preparePutIndexedScript("mustache", "testTemplate", "{" +
"\"template\":{" +
" \"query\":{" +
" \"match\":{" +
" \"theField\" : \"{{fieldParam}}\"}" +
" }" +
"}" +
"}").get();
assertEquals(scriptResponse.getVersion(), 2);
GetIndexedScriptResponse getResponse = client().prepareGetIndexedScript("mustache", "testTemplate").get();
assertTrue(getResponse.isExists());
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\"}"));
builders.add(client().prepareIndex("test", "type", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "type", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "type", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true,builders);
Map<String, String> templateParams = Maps.newHashMap();
templateParams.put("fieldParam", "foo");
SearchResponse searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("testTemplate").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
assertHitCount(searchResponse, 4);
DeleteIndexedScriptResponse deleteResponse = client().prepareDeleteIndexedScript("mustache","testTemplate").get();
assertTrue(deleteResponse.isFound() == true);
getResponse = client().prepareGetIndexedScript("mustache", "testTemplate").get();
assertFalse(getResponse.isExists());
Exception e = null;
try {
client().prepareSearch("test").setTypes("type").
setTemplateName("/template_index/mustache/1000").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
} catch (SearchPhaseExecutionException spee) {
e = spee;
}
assert e != null;
e = null;
}
@Test
public void testIndexedTemplate() throws Exception {
createIndex(ScriptService.SCRIPT_INDEX);
ensureGreen(ScriptService.SCRIPT_INDEX);
List<IndexRequestBuilder> builders = new ArrayList<IndexRequestBuilder>();
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "mustache", "1a").setSource("{" +
"\"template\":{"+
" \"query\":{" +
" \"match\":{" +
" \"theField\" : \"{{fieldParam}}\"}" +
" }" +
"}" +
"}"));
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "mustache", "2").setSource("{" +
"\"template\":{"+
" \"query\":{" +
" \"match\":{" +
" \"theField\" : \"{{fieldParam}}\"}" +
" }" +
"}" +
"}"));
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "mustache", "3").setSource("{" +
"\"template\":{"+
" \"match\":{" +
" \"theField\" : \"{{fieldParam}}\"}" +
" }" +
"}"));
indexRandom(true, builders);
builders.clear();
builders.add(client().prepareIndex("test", "type", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "type", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "type", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "type", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "type", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true,builders);
Map<String, String> templateParams = Maps.newHashMap();
templateParams.put("fieldParam", "foo");
SearchResponse searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("/mustache/1a").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
assertHitCount(searchResponse, 4);
Exception e = null;
try {
searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("/template_index/mustache/1000").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
} catch (SearchPhaseExecutionException spee) {
e = spee;
}
assert e != null;
e = null;
try {
searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("/myindex/mustache/1").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
assertFailures(searchResponse);
} catch (SearchPhaseExecutionException spee) {
e = spee;
}
assert e != null;
searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("1a").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
assertHitCount(searchResponse, 4);
templateParams.put("fieldParam", "bar");
searchResponse = client().prepareSearch("test").setTypes("type").
setTemplateName("/mustache/2").setTemplateType(ScriptService.ScriptType.INDEXED).setTemplateParams(templateParams).get();
assertHitCount(searchResponse, 1);
Map<String, Object> vars = new HashMap<>();
vars.put("fieldParam", "bar");
TemplateQueryBuilder builder = new TemplateQueryBuilder(
"3", ScriptService.ScriptType.INDEXED, vars);
SearchResponse sr = client().prepareSearch().setQuery(builder)
.execute().actionGet();
assertHitCount(sr, 1);
String query = "{\"template\": {\"id\": \"3\",\"params\" : {\"fieldParam\" : \"foo\"}}}";
sr = client().prepareSearch().setQuery(query).get();
assertHitCount(sr, 4);
query = "{\"template\": {\"id\": \"/mustache/3\",\"params\" : {\"fieldParam\" : \"foo\"}}}";
sr = client().prepareSearch().setQuery(query).get();
assertHitCount(sr, 4);
}
}

View File

@ -70,7 +70,7 @@ public class AliasRoutingTests extends ElasticsearchIntegrationTest {
logger.info("--> updating with id [1] and routing through alias");
client().prepareUpdate("alias0", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript("ctx._source.field = 'value2'")
.setInlineScript("ctx._source.field = 'value2'")
.execute().actionGet();
for (int i = 0; i < 5; i++) {
assertThat(client().prepareGet("alias0", "type1", "1").execute().actionGet().isExists(), equalTo(true));

View File

@ -0,0 +1,69 @@
/*
* 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.script;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
public class IndexedScriptTests extends ElasticsearchIntegrationTest {
@Test
public void testFieldIndexedScript() throws ExecutionException, InterruptedException{
List<IndexRequestBuilder> builders = new ArrayList();
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "groovy", "script1").setSource("{" +
"\"script\":\"2\""+
"}"));
builders.add(client().prepareIndex(ScriptService.SCRIPT_INDEX, "groovy", "script2").setSource("{" +
"\"script\":\"factor*2\""+
"}"));
indexRandom(true, builders);
builders.clear();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true,builders);
SearchResponse searchResponse;
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"id\" : \"script1\" }, \"test2\" : { \"id\" : \"script2\", \"params\":{\"factor\":3} }}, size:1}";
searchResponse = client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
assertHitCount(searchResponse,5);
assertTrue(searchResponse.getHits().hits().length == 1);
SearchHit sh = searchResponse.getHits().getAt(0);
assertTrue(sh.field("test1").getValue() == 2);
assertTrue(sh.field("test2").getValue() == 6);
}
}

View File

@ -46,7 +46,7 @@ public class NativeScriptTests extends ElasticsearchTestCase {
ScriptService scriptService = injector.getInstance(ScriptService.class);
ExecutableScript executable = scriptService.executable("native", "my", null);
ExecutableScript executable = scriptService.executable("native", "my", ScriptService.ScriptType.INLINE, null);
assertThat(executable.run().toString(), equalTo("test"));
}

View File

@ -0,0 +1,93 @@
/*
* 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.script;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
//Use Suite scope so that paths get set correctly
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE)
public class OnDiskScriptTests extends ElasticsearchIntegrationTest {
@Override
public Settings nodeSettings(int nodeOrdinal) {
//Set path so ScriptService will pick up the test scripts
return settingsBuilder().put("path.conf", this.getResource("config").getPath()).build();
}
@Test
public void testFieldOnDiskScript() throws ExecutionException, InterruptedException {
List<IndexRequestBuilder> builders = new ArrayList();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true,builders);
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"file\" : \"script1\" }, \"test2\" : { \"file\" : \"script2\", \"params\":{\"factor\":3} }}, size:1}";
SearchResponse searchResponse = client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
assertHitCount(searchResponse,5);
assertTrue(searchResponse.getHits().hits().length == 1);
SearchHit sh = searchResponse.getHits().getAt(0);
assertTrue(sh.field("test1").getValue() == 2);
assertTrue(sh.field("test2").getValue() == 6);
}
@Test
public void testFieldOnDiskBackwardCompatScript() throws ExecutionException, InterruptedException {
List<IndexRequestBuilder> builders = new ArrayList();
builders.add(client().prepareIndex("test", "scriptTest", "1").setSource("{\"theField\":\"foo\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "2").setSource("{\"theField\":\"foo 2\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "3").setSource("{\"theField\":\"foo 3\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "4").setSource("{\"theField\":\"foo 4\"}"));
builders.add(client().prepareIndex("test", "scriptTest", "5").setSource("{\"theField\":\"bar\"}"));
indexRandom(true,builders);
String query = "{ \"query\" : { \"match_all\": {}} , \"script_fields\" : { \"test1\" : { \"script\" : \"script1\" }, \"test2\" : { \"script\" : \"script2\", \"params\":{\"factor\":3} }}, size:1}";
SearchResponse searchResponse = client().prepareSearch().setSource(query).setIndices("test").setTypes("scriptTest").get();
assertHitCount(searchResponse,5);
assertTrue(searchResponse.getHits().hits().length == 1);
SearchHit sh = searchResponse.getHits().getAt(0);
assertTrue(sh.field("test1").getValue() == 2);
assertTrue(sh.field("test2").getValue() == 6);
}
}

View File

@ -58,7 +58,7 @@ public class UpdateByNativeScriptTests extends ElasticsearchIntegrationTest {
Map<String, Object> params = Maps.newHashMap();
params.put("foo", "SETVALUE");
client().prepareUpdate("test", "type", "1").setScript("custom").setScriptLang("native").setScriptParams(params).get();
client().prepareUpdate("test", "type", "1").setInlineScript("custom").setScriptLang("native").setScriptParams(params).get();
Map<String, Object> data = client().prepareGet("test", "type", "1").get().getSource();
assertThat(data, hasKey("foo"));

View File

@ -140,7 +140,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript("ctx._source.field += 1")
.setInlineScript("ctx._source.field += 1")
.execute().actionGet();
assertTrue(updateResponse.isCreated());
@ -151,7 +151,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript("ctx._source.field += 1")
.setInlineScript("ctx._source.field += 1")
.execute().actionGet();
assertFalse(updateResponse.isCreated());
@ -196,7 +196,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript("ctx._source.extra = \"foo\"")
.setInlineScript("ctx._source.extra = \"foo\"")
.setFields("_source")
.execute().actionGet();
@ -206,7 +206,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript("ctx._source.extra = \"foo\"")
.setInlineScript("ctx._source.extra = \"foo\"")
.setFields("_source")
.execute().actionGet();
@ -222,39 +222,40 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
index("test", "type", "1", "text", "value"); // version is now 1
assertThrows(client().prepareUpdate("test", "type", "1").setScript("ctx._source.text = 'v2'").setVersion(2).execute(),
assertThrows(client().prepareUpdate("test", "type", "1").setInlineScript("ctx._source.text = 'v2'").setVersion(2).execute(),
VersionConflictEngineException.class);
client().prepareUpdate("test", "type", "1").setScript("ctx._source.text = 'v2'").setVersion(1).get();
client().prepareUpdate("test", "type", "1").setInlineScript("ctx._source.text = 'v2'").setVersion(1).get();
assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(2l));
// and again with a higher version..
client().prepareUpdate("test", "type", "1").setScript("ctx._source.text = 'v3'").setVersion(2).get();
client().prepareUpdate("test", "type", "1").setInlineScript("ctx._source.text = 'v3'").setVersion(2).get();
assertThat(client().prepareGet("test", "type", "1").get().getVersion(), equalTo(3l));
// after delete
client().prepareDelete("test", "type", "1").get();
assertThrows(client().prepareUpdate("test", "type", "1").setScript("ctx._source.text = 'v2'").setVersion(3).execute(),
assertThrows(client().prepareUpdate("test", "type", "1").setInlineScript("ctx._source.text = 'v2'").setVersion(3).execute(),
DocumentMissingException.class);
// external versioning
client().prepareIndex("test", "type", "2").setSource("text", "value").setVersion(10).setVersionType(VersionType.EXTERNAL).get();
assertThrows(client().prepareUpdate("test", "type", "2").setScript("ctx._source.text = 'v2'").setVersion(2).setVersionType(VersionType.EXTERNAL).execute(),
ActionRequestValidationException.class);
assertThrows(client().prepareUpdate("test", "type", "2").setInlineScript("ctx._source.text = 'v2'").setVersion(2).setVersionType(VersionType.EXTERNAL).execute(),
ActionRequestValidationException.class);
// upserts - the combination with versions is a bit weird. Test are here to ensure we do not change our behavior unintentionally
// With internal versions, tt means "if object is there with version X, update it or explode. If it is not there, index.
client().prepareUpdate("test", "type", "3").setScript("ctx._source.text = 'v2'").setVersion(10).setUpsert("{ \"text\": \"v0\" }").get();
client().prepareUpdate("test", "type", "3").setInlineScript("ctx._source.text = 'v2'").setVersion(10).setUpsert("{ \"text\": \"v0\" }").get();
GetResponse get = get("test", "type", "3");
assertThat(get.getVersion(), equalTo(1l));
assertThat((String) get.getSource().get("text"), equalTo("v0"));
// With force version
client().prepareUpdate("test", "type", "4").setScript("ctx._source.text = 'v2'").
client().prepareUpdate("test", "type", "4").setInlineScript("ctx._source.text = 'v2'").
setVersion(10).setVersionType(VersionType.FORCE).setUpsert("{ \"text\": \"v0\" }").get();
get = get("test", "type", "4");
assertThat(get.getVersion(), equalTo(10l));
assertThat((String) get.getSource().get("text"), equalTo("v0"));
@ -270,7 +271,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
public void testIndexAutoCreation() throws Exception {
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript("ctx._source.extra = \"foo\"")
.setInlineScript("ctx._source.extra = \"foo\"")
.setFields("_source")
.execute().actionGet();
@ -285,7 +286,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
ensureGreen();
try {
client().prepareUpdate("test", "type1", "1").setScript("ctx._source.field++").execute().actionGet();
client().prepareUpdate("test", "type1", "1").setInlineScript("ctx._source.field++").execute().actionGet();
fail();
} catch (DocumentMissingException e) {
// all is well
@ -293,7 +294,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
client().prepareIndex("test", "type1", "1").setSource("field", 1).execute().actionGet();
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1").setScript("ctx._source.field += 1").execute().actionGet();
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1").setInlineScript("ctx._source.field += 1").execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(2L));
assertFalse(updateResponse.isCreated());
@ -302,7 +303,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
assertThat(getResponse.getSourceAsMap().get("field").toString(), equalTo("2"));
}
updateResponse = client().prepareUpdate("test", "type1", "1").setScript("ctx._source.field += count").addScriptParam("count", 3).execute().actionGet();
updateResponse = client().prepareUpdate("test", "type1", "1").setInlineScript("ctx._source.field += count").addScriptParam("count", 3).execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(3L));
assertFalse(updateResponse.isCreated());
@ -312,7 +313,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
}
// check noop
updateResponse = client().prepareUpdate("test", "type1", "1").setScript("ctx.op = 'none'").execute().actionGet();
updateResponse = client().prepareUpdate("test", "type1", "1").setInlineScript("ctx.op = 'none'").execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(3L));
assertFalse(updateResponse.isCreated());
@ -322,7 +323,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
}
// check delete
updateResponse = client().prepareUpdate("test", "type1", "1").setScript("ctx.op = 'delete'").execute().actionGet();
updateResponse = client().prepareUpdate("test", "type1", "1").setInlineScript("ctx.op = 'delete'").execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(4L));
assertFalse(updateResponse.isCreated());
@ -336,13 +337,13 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
GetResponse getResponse = client().prepareGet("test", "type1", "2").setFields("_ttl").execute().actionGet();
long ttl = ((Number) getResponse.getField("_ttl").getValue()).longValue();
assertThat(ttl, greaterThan(0L));
client().prepareUpdate("test", "type1", "2").setScript("ctx._source.field += 1").execute().actionGet();
client().prepareUpdate("test", "type1", "2").setInlineScript("ctx._source.field += 1").execute().actionGet();
getResponse = client().prepareGet("test", "type1", "2").setFields("_ttl").execute().actionGet();
ttl = ((Number) getResponse.getField("_ttl").getValue()).longValue();
assertThat(ttl, greaterThan(0L));
// check TTL update
client().prepareUpdate("test", "type1", "2").setScript("ctx._ttl = 3600000").execute().actionGet();
client().prepareUpdate("test", "type1", "2").setInlineScript("ctx._ttl = 3600000").execute().actionGet();
getResponse = client().prepareGet("test", "type1", "2").setFields("_ttl").execute().actionGet();
ttl = ((Number) getResponse.getField("_ttl").getValue()).longValue();
assertThat(ttl, greaterThan(0L));
@ -350,14 +351,14 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
// check timestamp update
client().prepareIndex("test", "type1", "3").setSource("field", 1).setRefresh(true).execute().actionGet();
client().prepareUpdate("test", "type1", "3").setScript("ctx._timestamp = \"2009-11-15T14:12:12\"").execute().actionGet();
client().prepareUpdate("test", "type1", "3").setInlineScript("ctx._timestamp = \"2009-11-15T14:12:12\"").execute().actionGet();
getResponse = client().prepareGet("test", "type1", "3").setFields("_timestamp").execute().actionGet();
long timestamp = ((Number) getResponse.getField("_timestamp").getValue()).longValue();
assertThat(timestamp, equalTo(1258294332000L));
// check fields parameter
client().prepareIndex("test", "type1", "1").setSource("field", 1).execute().actionGet();
updateResponse = client().prepareUpdate("test", "type1", "1").setScript("ctx._source.field += 1").setFields("_source", "field").execute().actionGet();
updateResponse = client().prepareUpdate("test", "type1", "1").setInlineScript("ctx._source.field += 1").setFields("_source", "field").execute().actionGet();
assertThat(updateResponse.getGetResult(), notNullValue());
assertThat(updateResponse.getGetResult().sourceRef(), notNullValue());
assertThat(updateResponse.getGetResult().field("field").getValue(), notNullValue());
@ -415,7 +416,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
try {
client().prepareUpdate("test", "type1", "1")
.setDoc(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript("ctx._source.field += 1")
.setInlineScript("ctx._source.field += 1")
.execute().actionGet();
fail("Should have thrown ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
@ -431,7 +432,7 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
ensureGreen();
try {
client().prepareUpdate("test", "type1", "1")
.setScript("ctx._source.field += 1")
.setInlineScript("ctx._source.field += 1")
.setDocAsUpsert(true)
.execute().actionGet();
fail("Should have thrown ActionRequestValidationException");
@ -464,12 +465,12 @@ public class UpdateTests extends ElasticsearchIntegrationTest {
for (int i = 0; i < numberOfUpdatesPerThread; i++) {
if (useBulkApi) {
UpdateRequestBuilder updateRequestBuilder = client().prepareUpdate("test", "type1", Integer.toString(i))
.setScript("ctx._source.field += 1")
.setInlineScript("ctx._source.field += 1")
.setRetryOnConflict(Integer.MAX_VALUE)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject());
client().prepareBulk().add(updateRequestBuilder).execute().actionGet();
} else {
client().prepareUpdate("test", "type1", Integer.toString(i)).setScript("ctx._source.field += 1")
client().prepareUpdate("test", "type1", Integer.toString(i)).setInlineScript("ctx._source.field += 1")
.setRetryOnConflict(Integer.MAX_VALUE)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject())
.execute().actionGet();

View File

@ -0,0 +1 @@
factor*2