Template cleanup:
* Removed `Template` class and unified script & template parsing logic. Templates are scripts, so they should be defined as a script. Unless there will be separate template infrastructure, templates should share as much code as possible with scripts. * Removed ScriptParseException in favour for ElasticsearchParseException * Moved TemplateQueryBuilder to lang-mustache module because this query is hard coded to work with mustache only
This commit is contained in:
parent
798ee177ed
commit
e0ebf5da1c
|
@ -658,8 +658,7 @@ public class ElasticsearchException extends RuntimeException implements ToXConte
|
|||
org.elasticsearch.search.aggregations.InvalidAggregationPathException::new, 121),
|
||||
INDEX_ALREADY_EXISTS_EXCEPTION(org.elasticsearch.indices.IndexAlreadyExistsException.class,
|
||||
org.elasticsearch.indices.IndexAlreadyExistsException::new, 123),
|
||||
SCRIPT_PARSE_EXCEPTION(org.elasticsearch.script.Script.ScriptParseException.class,
|
||||
org.elasticsearch.script.Script.ScriptParseException::new, 124),
|
||||
// 124 used to be Script.ScriptParseException
|
||||
HTTP_ON_TRANSPORT_EXCEPTION(TcpTransport.HttpOnTransportException.class,
|
||||
TcpTransport.HttpOnTransportException::new, 125),
|
||||
MAPPER_PARSING_EXCEPTION(org.elasticsearch.index.mapper.MapperParsingException.class,
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
|
|||
import org.elasticsearch.indices.TermsLookup;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
@ -621,27 +620,6 @@ public abstract class QueryBuilders {
|
|||
return new WrapperQueryBuilder(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Facilitates creating template query requests using an inline script
|
||||
*/
|
||||
public static TemplateQueryBuilder templateQuery(Template template) {
|
||||
return new TemplateQueryBuilder(template);
|
||||
}
|
||||
|
||||
/**
|
||||
* Facilitates creating template query requests using an inline script
|
||||
*/
|
||||
public static TemplateQueryBuilder templateQuery(String template, Map<String, Object> vars) {
|
||||
return new TemplateQueryBuilder(new Template(template, ScriptService.ScriptType.INLINE, null, null, vars));
|
||||
}
|
||||
|
||||
/**
|
||||
* Facilitates creating template query requests
|
||||
*/
|
||||
public static TemplateQueryBuilder templateQuery(String template, ScriptService.ScriptType templateType, Map<String, Object> vars) {
|
||||
return new TemplateQueryBuilder(new Template(template, templateType, null, null, vars));
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter based on doc/mapping type.
|
||||
*/
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.script.Script.ScriptField;
|
||||
import org.elasticsearch.script.Script.ScriptParseException;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public abstract class AbstractScriptParser<S extends Script> {
|
||||
|
||||
public abstract String parseInlineScript(XContentParser parser) throws IOException;
|
||||
|
||||
protected abstract S createScript(String script, ScriptType type, String lang, Map<String, Object> params);
|
||||
|
||||
protected abstract S createSimpleScript(XContentParser parser) throws IOException;
|
||||
|
||||
public S parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
|
||||
|
||||
XContentParser.Token token = parser.currentToken();
|
||||
// If the parser hasn't yet been pushed to the first token, do it now
|
||||
if (token == null) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
return createSimpleScript(parser);
|
||||
}
|
||||
if (token != XContentParser.Token.START_OBJECT) {
|
||||
throw new ScriptParseException("expected a string value or an object, but found [{}] instead", token);
|
||||
}
|
||||
|
||||
String script = null;
|
||||
ScriptType type = null;
|
||||
String lang = getDefaultScriptLang();
|
||||
Map<String, Object> params = null;
|
||||
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptType.INLINE.getParseField())) {
|
||||
type = ScriptType.INLINE;
|
||||
script = parseInlineScript(parser);
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptType.FILE.getParseField())) {
|
||||
type = ScriptType.FILE;
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
script = parser.text();
|
||||
} else {
|
||||
throw new ScriptParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptType.STORED.getParseField())) {
|
||||
type = ScriptType.STORED;
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
script = parser.text();
|
||||
} else {
|
||||
throw new ScriptParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptField.LANG)) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
lang = parser.text();
|
||||
} else {
|
||||
throw new ScriptParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(currentFieldName, ScriptField.PARAMS)) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
params = parser.map();
|
||||
} else {
|
||||
throw new ScriptParseException("expected an object for field [{}], but found [{}]", currentFieldName, token);
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("unexpected field [{}]", currentFieldName);
|
||||
}
|
||||
}
|
||||
if (script == null) {
|
||||
throw new ScriptParseException("expected one of [{}], [{}] or [{}] fields, but found none", ScriptType.INLINE.getParseField()
|
||||
.getPreferredName(), ScriptType.FILE.getParseField().getPreferredName(), ScriptType.STORED.getParseField()
|
||||
.getPreferredName());
|
||||
}
|
||||
assert type != null : "if script is not null, type should definitely not be null";
|
||||
return createScript(script, type, lang, params);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default script language for this parser or <code>null</code>
|
||||
* to use the default set in the ScriptService
|
||||
*/
|
||||
protected String getDefaultScriptLang() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public S parse(Map<String, Object> config, boolean removeMatchedEntries, ParseFieldMatcher parseFieldMatcher) {
|
||||
String script = null;
|
||||
ScriptType type = null;
|
||||
String lang = null;
|
||||
Map<String, Object> params = null;
|
||||
for (Iterator<Entry<String, Object>> itr = config.entrySet().iterator(); itr.hasNext();) {
|
||||
Entry<String, Object> entry = itr.next();
|
||||
String parameterName = entry.getKey();
|
||||
Object parameterValue = entry.getValue();
|
||||
if (parseFieldMatcher.match(parameterName, ScriptField.LANG)) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
lang = (String) parameterValue;
|
||||
if (removeMatchedEntries) {
|
||||
itr.remove();
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptField.PARAMS)) {
|
||||
if (parameterValue instanceof Map || parameterValue == null) {
|
||||
params = (Map<String, Object>) parameterValue;
|
||||
if (removeMatchedEntries) {
|
||||
itr.remove();
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptType.INLINE.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptType.INLINE;
|
||||
if (removeMatchedEntries) {
|
||||
itr.remove();
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptType.FILE.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptType.FILE;
|
||||
if (removeMatchedEntries) {
|
||||
itr.remove();
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptType.STORED.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptType.STORED;
|
||||
if (removeMatchedEntries) {
|
||||
itr.remove();
|
||||
}
|
||||
} else {
|
||||
throw new ScriptParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (script == null) {
|
||||
throw new ScriptParseException("expected one of [{}], [{}] or [{}] fields, but found none", ScriptType.INLINE.getParseField()
|
||||
.getPreferredName(), ScriptType.FILE.getParseField().getPreferredName(), ScriptType.STORED.getParseField()
|
||||
.getPreferredName());
|
||||
}
|
||||
assert type != null : "if script is not null, type should definitely not be null";
|
||||
return createScript(script, type, lang, params);
|
||||
}
|
||||
|
||||
}
|
|
@ -19,79 +19,75 @@
|
|||
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
import org.elasticsearch.common.logging.LoggerMessageFormat;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Script holds all the parameters necessary to compile or find in cache and then execute a script.
|
||||
*/
|
||||
public class Script implements ToXContent, Writeable {
|
||||
public final class Script implements ToXContent, Writeable {
|
||||
|
||||
public static final ScriptType DEFAULT_TYPE = ScriptType.INLINE;
|
||||
private static final ScriptParser PARSER = new ScriptParser();
|
||||
|
||||
private String script;
|
||||
@Nullable private ScriptType type;
|
||||
private ScriptType type;
|
||||
@Nullable private String lang;
|
||||
@Nullable private Map<String, Object> params;
|
||||
@Nullable private XContentType contentType;
|
||||
|
||||
/**
|
||||
* Constructor for simple inline script. The script will have no lang or
|
||||
* params set.
|
||||
* Constructor for simple inline script. The script will have no lang or params set.
|
||||
*
|
||||
* @param script
|
||||
* The inline script to execute.
|
||||
* @param script The inline script to execute.
|
||||
*/
|
||||
public Script(String script) {
|
||||
this(script, null);
|
||||
this(script, ScriptType.INLINE, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* For sub-classes to use to override the default language
|
||||
*/
|
||||
protected Script(String script, String lang) {
|
||||
this(script, ScriptType.INLINE, lang, null);
|
||||
public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map<String, ?> params) {
|
||||
this(script, type, lang, params, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Script.
|
||||
*
|
||||
* @param script
|
||||
* The cache key of the script to be compiled/executed. For
|
||||
* inline scripts this is the actual script source code. For
|
||||
* indexed scripts this is the id used in the request. For on
|
||||
* file scripts this is the file name.
|
||||
* @param type
|
||||
* The type of script -- dynamic, indexed, or file.
|
||||
* @param lang
|
||||
* The language of the script to be compiled/executed.
|
||||
* @param params
|
||||
* The map of parameters the script will be executed with.
|
||||
* @param script The cache key of the script to be compiled/executed. For inline scripts this is the actual
|
||||
* script source code. For indexed scripts this is the id used in the request. For on file
|
||||
* scripts this is the file name.
|
||||
* @param type The type of script -- dynamic, stored, or file.
|
||||
* @param lang The language of the script to be compiled/executed.
|
||||
* @param params The map of parameters the script will be executed with.
|
||||
* @param contentType The {@link XContentType} of the script. Only relevant for inline scripts that have not been
|
||||
* defined as a plain string, but as json or yaml content. This class needs this information
|
||||
* when serializing the script back to xcontent.
|
||||
*/
|
||||
public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map<String, ? extends Object> params) {
|
||||
if (script == null) {
|
||||
throw new IllegalArgumentException("The parameter script (String) must not be null in Script.");
|
||||
@SuppressWarnings("unchecked")
|
||||
public Script(String script, ScriptType type, @Nullable String lang, @Nullable Map<String, ?> params,
|
||||
@Nullable XContentType contentType) {
|
||||
if (contentType != null && type != ScriptType.INLINE) {
|
||||
throw new IllegalArgumentException("The parameter contentType only makes sense for inline scripts");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("The parameter type (ScriptType) must not be null in Script.");
|
||||
}
|
||||
this.script = script;
|
||||
this.type = type;
|
||||
this.script = Objects.requireNonNull(script);
|
||||
this.type = Objects.requireNonNull(type);
|
||||
this.lang = lang;
|
||||
this.params = (Map<String, Object>)params;
|
||||
this.params = (Map<String, Object>) params;
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public Script(StreamInput in) throws IOException {
|
||||
|
@ -100,13 +96,14 @@ public class Script implements ToXContent, Writeable {
|
|||
type = ScriptType.readFrom(in);
|
||||
}
|
||||
lang = in.readOptionalString();
|
||||
params = in.readMap();
|
||||
if (in.readBoolean()) {
|
||||
params = in.readMap();
|
||||
contentType = XContentType.readFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void writeTo(StreamOutput out) throws IOException {
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(script);
|
||||
boolean hasType = type != null;
|
||||
out.writeBoolean(hasType);
|
||||
|
@ -114,16 +111,14 @@ public class Script implements ToXContent, Writeable {
|
|||
ScriptType.writeTo(type, out);
|
||||
}
|
||||
out.writeOptionalString(lang);
|
||||
boolean hasParams = params != null;
|
||||
out.writeBoolean(hasParams);
|
||||
if (hasParams) {
|
||||
out.writeMap(params);
|
||||
out.writeMap(params);
|
||||
boolean hasContentType = contentType != null;
|
||||
out.writeBoolean(hasContentType);
|
||||
if (hasContentType) {
|
||||
XContentType.writeTo(contentType, out);
|
||||
}
|
||||
doWriteTo(out);
|
||||
}
|
||||
|
||||
protected void doWriteTo(StreamOutput out) throws IOException {};
|
||||
|
||||
/**
|
||||
* Method for getting the script.
|
||||
* @return The cache key of the script to be compiled/executed. For dynamic scripts this is the actual
|
||||
|
@ -137,7 +132,7 @@ public class Script implements ToXContent, Writeable {
|
|||
/**
|
||||
* Method for getting the type.
|
||||
*
|
||||
* @return The type of script -- inline, indexed, or file.
|
||||
* @return The type of script -- inline, stored, or file.
|
||||
*/
|
||||
public ScriptType getType() {
|
||||
return type == null ? DEFAULT_TYPE : type;
|
||||
|
@ -161,14 +156,25 @@ public class Script implements ToXContent, Writeable {
|
|||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The content type of the script if it is an inline script and the script has been defined as json
|
||||
* or yaml content instead of a plain string.
|
||||
*/
|
||||
public XContentType getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException {
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params builderParams) throws IOException {
|
||||
if (type == null) {
|
||||
return builder.value(script);
|
||||
}
|
||||
|
||||
builder.startObject();
|
||||
scriptFieldToXContent(script, type, builder, builderParams);
|
||||
if (type == ScriptType.INLINE && contentType != null && builder.contentType() == contentType) {
|
||||
builder.rawField(type.getParseField().getPreferredName(), new BytesArray(script));
|
||||
} else {
|
||||
builder.field(type.getParseField().getPreferredName(), script);
|
||||
}
|
||||
if (lang != null) {
|
||||
builder.field(ScriptField.LANG.getPreferredName(), lang);
|
||||
}
|
||||
|
@ -179,29 +185,80 @@ public class Script implements ToXContent, Writeable {
|
|||
return builder;
|
||||
}
|
||||
|
||||
protected XContentBuilder scriptFieldToXContent(String script, ScriptType type, XContentBuilder builder, Params builderParams)
|
||||
throws IOException {
|
||||
builder.field(type.getParseField().getPreferredName(), script);
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Script parse(Map<String, Object> config, boolean removeMatchedEntries, ParseFieldMatcher parseFieldMatcher) {
|
||||
return PARSER.parse(config, removeMatchedEntries, parseFieldMatcher);
|
||||
}
|
||||
|
||||
public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
|
||||
return PARSER.parse(parser, parseFieldMatcher);
|
||||
return parse(parser, parseFieldMatcher, null);
|
||||
}
|
||||
|
||||
public static Script parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher, @Nullable String lang) throws IOException {
|
||||
XContentParser.Token token = parser.currentToken();
|
||||
// If the parser hasn't yet been pushed to the first token, do it now
|
||||
if (token == null) {
|
||||
token = parser.nextToken();
|
||||
}
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
return new Script(parser.text());
|
||||
}
|
||||
if (token != XContentParser.Token.START_OBJECT) {
|
||||
throw new ElasticsearchParseException("expected a string value or an object, but found [{}] instead", token);
|
||||
}
|
||||
String script = null;
|
||||
ScriptType type = null;
|
||||
Map<String, Object> params = null;
|
||||
XContentType contentType = null;
|
||||
String cfn = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
cfn = parser.currentName();
|
||||
} else if (parseFieldMatcher.match(cfn, ScriptType.INLINE.getParseField())) {
|
||||
type = ScriptType.INLINE;
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||
contentType = parser.contentType();
|
||||
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
|
||||
script = builder.copyCurrentStructure(parser).bytes().utf8ToString();
|
||||
} else {
|
||||
script = parser.text();
|
||||
}
|
||||
} else if (parseFieldMatcher.match(cfn, ScriptType.FILE.getParseField())) {
|
||||
type = ScriptType.FILE;
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
script = parser.text();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(cfn, ScriptType.STORED.getParseField())) {
|
||||
type = ScriptType.STORED;
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
script = parser.text();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(cfn, ScriptField.LANG)) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
lang = parser.text();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("expected a string value for field [{}], but found [{}]", cfn, token);
|
||||
}
|
||||
} else if (parseFieldMatcher.match(cfn, ScriptField.PARAMS)) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
params = parser.map();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("expected an object for field [{}], but found [{}]", cfn, token);
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("unexpected field [{}]", cfn);
|
||||
}
|
||||
}
|
||||
if (script == null) {
|
||||
throw new ElasticsearchParseException("expected one of [{}], [{}] or [{}] fields, but found none",
|
||||
ScriptType.INLINE.getParseField() .getPreferredName(), ScriptType.FILE.getParseField().getPreferredName(),
|
||||
ScriptType.STORED.getParseField() .getPreferredName());
|
||||
}
|
||||
return new Script(script, type, lang, params, contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((lang == null) ? 0 : lang.hashCode());
|
||||
result = prime * result + ((params == null) ? 0 : params.hashCode());
|
||||
result = prime * result + ((script == null) ? 0 : script.hashCode());
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
return Objects.hash(lang, params, script, type, contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,52 +267,18 @@ public class Script implements ToXContent, Writeable {
|
|||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Script other = (Script) obj;
|
||||
if (lang == null) {
|
||||
if (other.lang != null) return false;
|
||||
} else {
|
||||
if (!lang.equals(other.lang)) return false;
|
||||
}
|
||||
if (params == null) {
|
||||
if (other.params != null) return false;
|
||||
} else {
|
||||
if (!params.equals(other.params)) return false;
|
||||
}
|
||||
if (script == null) {
|
||||
if (other.script != null) return false;
|
||||
} else {
|
||||
if (!script.equals(other.script)) return false;
|
||||
}
|
||||
if (type != other.type) return false;
|
||||
return true;
|
||||
|
||||
return Objects.equals(lang, other.lang) &&
|
||||
Objects.equals(params, other.params) &&
|
||||
Objects.equals(script, other.script) &&
|
||||
Objects.equals(type, other.type) &&
|
||||
Objects.equals(contentType, other.contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[script: " + script + ", type: " + type.getParseField().getPreferredName() + ", lang: " + lang + ", params: " + params
|
||||
+ "]";
|
||||
}
|
||||
|
||||
private static class ScriptParser extends AbstractScriptParser<Script> {
|
||||
|
||||
@Override
|
||||
protected Script createSimpleScript(XContentParser parser) throws IOException {
|
||||
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
|
||||
return new Script(parser.text());
|
||||
} else {
|
||||
throw new ScriptParseException("expected a string value for field [{}], but found [{}]", parser.currentName(),
|
||||
parser.currentToken());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Script createScript(String script, ScriptType type, String lang, Map<String, Object> params) {
|
||||
return new Script(script, type, lang, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseInlineScript(XContentParser parser) throws IOException {
|
||||
return parser.text();
|
||||
}
|
||||
return "[script: " + script + ", type: " + type.getParseField().getPreferredName() + ", lang: "
|
||||
+ lang + ", params: " + params + "]";
|
||||
}
|
||||
|
||||
public interface ScriptField {
|
||||
|
@ -264,14 +287,4 @@ public class Script implements ToXContent, Writeable {
|
|||
ParseField PARAMS = new ParseField("params");
|
||||
}
|
||||
|
||||
public static class ScriptParseException extends ElasticsearchException {
|
||||
|
||||
public ScriptParseException(String msg, Object... args) {
|
||||
super(LoggerMessageFormat.format(msg, args));
|
||||
}
|
||||
|
||||
public ScriptParseException(StreamInput in) throws IOException{
|
||||
super(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class Template extends Script {
|
||||
|
||||
/** Default templating language */
|
||||
public static final String DEFAULT_LANG = "mustache";
|
||||
|
||||
private XContentType contentType;
|
||||
|
||||
/**
|
||||
* Constructor for simple inline template. The template will have no lang,
|
||||
* content type or params set.
|
||||
*
|
||||
* @param template
|
||||
* The inline template.
|
||||
*/
|
||||
public Template(String template) {
|
||||
super(template, DEFAULT_LANG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Template.
|
||||
*
|
||||
* @param template
|
||||
* The cache key of the template to be compiled/executed. For
|
||||
* inline templates this is the actual templates source code. For
|
||||
* indexed templates this is the id used in the request. For on
|
||||
* file templates this is the file name.
|
||||
* @param type
|
||||
* The type of template -- dynamic, indexed, or file.
|
||||
* @param lang
|
||||
* The language of the template to be compiled/executed.
|
||||
* @param xContentType
|
||||
* The {@link XContentType} of the template.
|
||||
* @param params
|
||||
* The map of parameters the template will be executed with.
|
||||
*/
|
||||
public Template(String template, ScriptType type, @Nullable String lang, @Nullable XContentType xContentType,
|
||||
@Nullable Map<String, Object> params) {
|
||||
super(template, type, lang == null ? DEFAULT_LANG : lang, params);
|
||||
this.contentType = xContentType;
|
||||
}
|
||||
|
||||
public Template(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
if (in.readBoolean()) {
|
||||
this.contentType = XContentType.readFrom(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doWriteTo(StreamOutput out) throws IOException {
|
||||
boolean hasContentType = contentType != null;
|
||||
out.writeBoolean(hasContentType);
|
||||
if (hasContentType) {
|
||||
XContentType.writeTo(contentType, out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for getting the {@link XContentType} of the template.
|
||||
*
|
||||
* @return The {@link XContentType} of the template.
|
||||
*/
|
||||
public XContentType getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XContentBuilder scriptFieldToXContent(String template, ScriptType type, XContentBuilder builder, Params builderParams)
|
||||
throws IOException {
|
||||
if (type == ScriptType.INLINE && contentType != null && builder.contentType() == contentType) {
|
||||
builder.rawField(type.getParseField().getPreferredName(), new BytesArray(template));
|
||||
} else {
|
||||
builder.field(type.getParseField().getPreferredName(), template);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static Script parse(Map<String, Object> config, boolean removeMatchedEntries, ParseFieldMatcher parseFieldMatcher) {
|
||||
return new TemplateParser(DEFAULT_LANG).parse(config, removeMatchedEntries, parseFieldMatcher);
|
||||
}
|
||||
|
||||
public static Template parse(XContentParser parser, ParseFieldMatcher parseFieldMatcher) throws IOException {
|
||||
return new TemplateParser(DEFAULT_LANG).parse(parser, parseFieldMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((contentType == null) ? 0 : contentType.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!super.equals(obj)) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Template other = (Template) obj;
|
||||
if (contentType != other.contentType) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class TemplateParser extends AbstractScriptParser<Template> {
|
||||
|
||||
private XContentType contentType = null;
|
||||
private String defaultLang;
|
||||
|
||||
public TemplateParser(String defaultLang) {
|
||||
this.defaultLang = defaultLang;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Template createSimpleScript(XContentParser parser) throws IOException {
|
||||
return new Template(String.valueOf(parser.objectText()), ScriptType.INLINE, DEFAULT_LANG, contentType, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Template createScript(String script, ScriptType type, String lang, Map<String, Object> params) {
|
||||
return new Template(script, type, lang, contentType, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseInlineScript(XContentParser parser) throws IOException {
|
||||
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
|
||||
contentType = parser.contentType();
|
||||
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
|
||||
return builder.copyCurrentStructure(parser).bytes().utf8ToString();
|
||||
} else {
|
||||
return parser.text();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultScriptLang() {
|
||||
return defaultLang;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,7 +75,6 @@ import org.elasticsearch.index.query.SpanNotQueryBuilder;
|
|||
import org.elasticsearch.index.query.SpanOrQueryBuilder;
|
||||
import org.elasticsearch.index.query.SpanTermQueryBuilder;
|
||||
import org.elasticsearch.index.query.SpanWithinQueryBuilder;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||
import org.elasticsearch.index.query.TermsQueryBuilder;
|
||||
import org.elasticsearch.index.query.TypeQueryBuilder;
|
||||
|
@ -795,7 +794,6 @@ public class SearchModule extends AbstractModule {
|
|||
registerQuery(FunctionScoreQueryBuilder::new, c -> FunctionScoreQueryBuilder.fromXContent(scoreFunctionParserRegistry, c),
|
||||
FunctionScoreQueryBuilder.QUERY_NAME_FIELD);
|
||||
registerQuery(SimpleQueryStringBuilder::new, SimpleQueryStringBuilder::fromXContent, SimpleQueryStringBuilder.QUERY_NAME_FIELD);
|
||||
registerQuery(TemplateQueryBuilder::new, TemplateQueryBuilder::fromXContent, TemplateQueryBuilder.QUERY_NAME_FIELD);
|
||||
registerQuery(TypeQueryBuilder::new, TypeQueryBuilder::fromXContent, TypeQueryBuilder.QUERY_NAME_FIELD);
|
||||
registerQuery(ScriptQueryBuilder::new, ScriptQueryBuilder::fromXContent, ScriptQueryBuilder.QUERY_NAME_FIELD);
|
||||
registerQuery(GeoDistanceQueryBuilder::new, GeoDistanceQueryBuilder::fromXContent, GeoDistanceQueryBuilder.QUERY_NAME_FIELD);
|
||||
|
|
|
@ -36,8 +36,9 @@ import org.elasticsearch.index.mapper.MapperService;
|
|||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.script.CompiledScript;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.suggest.SuggestUtils;
|
||||
import org.elasticsearch.search.suggest.SuggestionBuilder;
|
||||
import org.elasticsearch.search.suggest.SuggestionSearchContext.SuggestionContext;
|
||||
|
@ -87,7 +88,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB
|
|||
private int tokenLimit = NoisyChannelSpellChecker.DEFAULT_TOKEN_LIMIT;
|
||||
private String preTag;
|
||||
private String postTag;
|
||||
private Template collateQuery;
|
||||
private Script collateQuery;
|
||||
private Map<String, Object> collateParams;
|
||||
private boolean collatePrune = PhraseSuggestionContext.DEFAULT_COLLATE_PRUNE;
|
||||
private SmoothingModel model;
|
||||
|
@ -135,7 +136,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB
|
|||
postTag = in.readOptionalString();
|
||||
separator = in.readString();
|
||||
if (in.readBoolean()) {
|
||||
collateQuery = new Template(in);
|
||||
collateQuery = new Script(in);
|
||||
}
|
||||
collateParams = in.readMap();
|
||||
collatePrune = in.readOptionalBoolean();
|
||||
|
@ -389,14 +390,14 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB
|
|||
* Sets a query used for filtering out suggested phrases (collation).
|
||||
*/
|
||||
public PhraseSuggestionBuilder collateQuery(String collateQuery) {
|
||||
this.collateQuery = new Template(collateQuery);
|
||||
this.collateQuery = new Script(collateQuery, ScriptService.ScriptType.INLINE, "mustache", Collections.emptyMap());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a query used for filtering out suggested phrases (collation).
|
||||
*/
|
||||
public PhraseSuggestionBuilder collateQuery(Template collateQueryTemplate) {
|
||||
public PhraseSuggestionBuilder collateQuery(Script collateQueryTemplate) {
|
||||
this.collateQuery = collateQueryTemplate;
|
||||
return this;
|
||||
}
|
||||
|
@ -404,7 +405,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB
|
|||
/**
|
||||
* gets the query used for filtering out suggested phrases (collation).
|
||||
*/
|
||||
public Template collateQuery() {
|
||||
public Script collateQuery() {
|
||||
return this.collateQuery;
|
||||
}
|
||||
|
||||
|
@ -563,7 +564,7 @@ public class PhraseSuggestionBuilder extends SuggestionBuilder<PhraseSuggestionB
|
|||
"suggester[phrase][collate] query already set, doesn't support additional ["
|
||||
+ currentFieldName + "]");
|
||||
}
|
||||
Template template = Template.parse(parser, parseFieldMatcher);
|
||||
Script template = Script.parse(parser, parseFieldMatcher, "mustache");
|
||||
tmpSuggestion.collateQuery(template);
|
||||
} else if (parseFieldMatcher.match(currentFieldName, PhraseSuggestionBuilder.COLLATE_QUERY_PARAMS)) {
|
||||
tmpSuggestion.collateParams(parser.map());
|
||||
|
|
|
@ -771,7 +771,7 @@ public class ExceptionSerializationTests extends ESTestCase {
|
|||
ids.put(121, org.elasticsearch.search.aggregations.InvalidAggregationPathException.class);
|
||||
ids.put(122, null);
|
||||
ids.put(123, org.elasticsearch.indices.IndexAlreadyExistsException.class);
|
||||
ids.put(124, org.elasticsearch.script.Script.ScriptParseException.class);
|
||||
ids.put(124, null);
|
||||
ids.put(125, TcpTransport.HttpOnTransportException.class);
|
||||
ids.put(126, org.elasticsearch.index.mapper.MapperParsingException.class);
|
||||
ids.put(127, org.elasticsearch.search.SearchContextException.class);
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.elasticsearch.index.mapper.Uid;
|
|||
import org.elasticsearch.index.mapper.internal.TypeFieldMapper;
|
||||
import org.elasticsearch.index.mapper.internal.UidFieldMapper;
|
||||
import org.elasticsearch.index.similarity.SimilarityService;
|
||||
import org.elasticsearch.script.Script.ScriptParseException;
|
||||
import org.elasticsearch.search.fetch.innerhits.InnerHitsContext;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
|
@ -310,7 +309,7 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
|
|||
try {
|
||||
parseQuery(testQuery);
|
||||
fail("some parsing exception expected for query: " + testQuery);
|
||||
} catch (ParsingException | ScriptParseException | ElasticsearchParseException e) {
|
||||
} catch (ParsingException | ElasticsearchParseException e) {
|
||||
// different kinds of exception wordings depending on location
|
||||
// of mutation, so no simple asserts possible here
|
||||
} catch (JsonParseException e) {
|
||||
|
|
|
@ -34,14 +34,11 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.script.Script.ScriptParseException;
|
||||
import org.elasticsearch.search.fetch.innerhits.InnerHitsContext;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
@ -202,7 +199,7 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ
|
|||
try {
|
||||
parseQuery(testQuery);
|
||||
fail("some parsing exception expected for query: " + testQuery);
|
||||
} catch (ParsingException | ScriptParseException | ElasticsearchParseException e) {
|
||||
} catch (ParsingException | ElasticsearchParseException e) {
|
||||
// different kinds of exception wordings depending on location
|
||||
// of mutation, so no simple asserts possible here
|
||||
} catch (JsonParseException e) {
|
||||
|
|
|
@ -196,7 +196,7 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu
|
|||
try {
|
||||
parseQuery(testQuery);
|
||||
fail("some parsing exception expected for query: " + testQuery);
|
||||
} catch (ParsingException | Script.ScriptParseException | ElasticsearchParseException e) {
|
||||
} catch (ParsingException | ElasticsearchParseException e) {
|
||||
// different kinds of exception wordings depending on location
|
||||
// of mutation, so no simple asserts possible here
|
||||
} catch (JsonParseException e) {
|
||||
|
|
|
@ -76,7 +76,6 @@ import static org.elasticsearch.index.query.QueryBuilders.spanNotQuery;
|
|||
import static org.elasticsearch.index.query.QueryBuilders.spanOrQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.spanTermQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.spanWithinQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.templateQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.typeQuery;
|
||||
|
@ -359,13 +358,6 @@ public class QueryDSLDocumentationTests extends ESTestCase {
|
|||
spanTermQuery("field1", "foo"));
|
||||
}
|
||||
|
||||
public void testTemplate() {
|
||||
templateQuery(
|
||||
"gender_template",
|
||||
ScriptType.STORED,
|
||||
new HashMap<>());
|
||||
}
|
||||
|
||||
public void testTerm() {
|
||||
termQuery("name", "kimchy");
|
||||
}
|
||||
|
|
|
@ -225,7 +225,6 @@ public class SearchModuleTests extends ModuleTestCase {
|
|||
"span_or",
|
||||
"span_term",
|
||||
"span_within",
|
||||
"template",
|
||||
"term",
|
||||
"terms",
|
||||
"type",
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
package org.elasticsearch.search.suggest.phrase;
|
||||
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.search.suggest.AbstractSuggestionBuilderTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -109,7 +109,7 @@ public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestC
|
|||
builder.separator(randomValueOtherThan(builder.separator(), () -> randomAsciiOfLengthBetween(1, 10)));
|
||||
break;
|
||||
case 6:
|
||||
Template collateQuery = builder.collateQuery();
|
||||
Script collateQuery = builder.collateQuery();
|
||||
if (collateQuery != null) {
|
||||
builder.collateQuery(randomValueOtherThan(collateQuery.getScript(), () -> randomAsciiOfLengthBetween(3, 20)));
|
||||
} else {
|
||||
|
@ -156,7 +156,7 @@ public class PhraseSuggestionBuilderTests extends AbstractSuggestionBuilderTestC
|
|||
assertEquals("suggestion field name is empty", e.getMessage());
|
||||
|
||||
PhraseSuggestionBuilder builder = new PhraseSuggestionBuilder(randomAsciiOfLengthBetween(2, 20));
|
||||
|
||||
|
||||
e = expectThrows(IllegalArgumentException.class, () -> builder.gramSize(0));
|
||||
assertEquals("gramSize must be >= 1", e.getMessage());
|
||||
e = expectThrows(IllegalArgumentException.class, () -> builder.gramSize(-1));
|
||||
|
|
|
@ -3,6 +3,21 @@
|
|||
|
||||
See {ref}/search-template.html[Search Template] documentation
|
||||
|
||||
In order to use the `template` query from the Java API
|
||||
the lang-mustache module dependency should be on the classpath and
|
||||
the transport client should be loaded with the lang-mustache plugin:
|
||||
|
||||
[source,java]
|
||||
--------------------------------------------------
|
||||
TransportClient transportClient = TransportClient.builder()
|
||||
.settings(Settings.builder().put("node.name", "node"))
|
||||
.addPlugin(MustachePlugin.class)
|
||||
.build();
|
||||
transportClient.addTransportAddress(
|
||||
new InetSocketTransportAddress(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9300))
|
||||
);
|
||||
--------------------------------------------------
|
||||
|
||||
Define your template parameters as a `Map<String,Object>`:
|
||||
|
||||
[source,java]
|
||||
|
@ -31,7 +46,7 @@ Define your template query:
|
|||
|
||||
[source,java]
|
||||
--------------------------------------------------
|
||||
QueryBuilder qb = templateQuery(
|
||||
QueryBuilder qb = new TemplateQueryBuilder(
|
||||
"gender_template", <1>
|
||||
ScriptService.ScriptType.FILE, <2>
|
||||
template_params); <3>
|
||||
|
@ -40,11 +55,14 @@ QueryBuilder qb = templateQuery(
|
|||
<2> template stored on disk in `gender_template.mustache`
|
||||
<3> parameters
|
||||
|
||||
You can also store your template in a special index named `.scripts`:
|
||||
You can also store your template in the cluster state:
|
||||
|
||||
[source,java]
|
||||
--------------------------------------------------
|
||||
client.preparePutIndexedScript("mustache", "template_gender",
|
||||
client.admin().cluster().preparePutStoredScript()
|
||||
.setScriptLang("mustache")
|
||||
.setId("template_gender")
|
||||
.setSource(new BytesArray(
|
||||
"{\n" +
|
||||
" \"template\" : {\n" +
|
||||
" \"query\" : {\n" +
|
||||
|
@ -53,19 +71,19 @@ client.preparePutIndexedScript("mustache", "template_gender",
|
|||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}").get();
|
||||
"}")).get();
|
||||
--------------------------------------------------
|
||||
|
||||
To execute an indexed templates, use `ScriptService.ScriptType.INDEXED`:
|
||||
To execute a stored templates, use `ScriptService.ScriptType.STORED`:
|
||||
|
||||
[source,java]
|
||||
--------------------------------------------------
|
||||
QueryBuilder qb = templateQuery(
|
||||
QueryBuilder qb = new TemplateQueryBuilder(
|
||||
"gender_template", <1>
|
||||
ScriptType.INDEXED, <2>
|
||||
ScriptType.STORED, <2>
|
||||
template_params); <3>
|
||||
--------------------------------------------------
|
||||
<1> template name
|
||||
<2> template stored in an index
|
||||
<2> template stored in the cluster state
|
||||
<3> parameters
|
||||
|
||||
|
|
|
@ -289,3 +289,24 @@ registers the "js" file extension for on-disk scripts.
|
|||
==== Removed scripting query string parameters from update rest api
|
||||
|
||||
The `script`, `script_id` and `scripting_upsert` query string parameters have been removed from the update api.
|
||||
|
||||
==== Java transport client
|
||||
|
||||
The `TemplateQueryBuilder` has been moved to the `lang-mustache` module.
|
||||
Therefor when using the `TemplateQueryBuilder` from the Java native client the
|
||||
lang-mustache module should be on the classpath. Also the transport client
|
||||
should load the lang-mustache module as plugin:
|
||||
|
||||
[source,java]
|
||||
--------------------------------------------------
|
||||
TransportClient transportClient = TransportClient.builder()
|
||||
.settings(Settings.builder().put("node.name", "node"))
|
||||
.addPlugin(MustachePlugin.class)
|
||||
.build();
|
||||
transportClient.addTransportAddress(
|
||||
new InetSocketTransportAddress(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9300))
|
||||
);
|
||||
--------------------------------------------------
|
||||
|
||||
Also the helper methods in `QueryBuilders` class that create a `TemplateQueryBuilder` instance have been removed,
|
||||
instead the constructors on `TemplateQueryBuilder` should be used.
|
|
@ -42,7 +42,7 @@ public class ScriptProcessorTests extends ESTestCase {
|
|||
int randomInt = randomInt();
|
||||
ScriptService scriptService = mock(ScriptService.class);
|
||||
CompiledScript compiledScript = mock(CompiledScript.class);
|
||||
Script script = mock(Script.class);
|
||||
Script script = new Script("_script");
|
||||
when(scriptService.compile(any(), any(), any())).thenReturn(compiledScript);
|
||||
ExecutableScript executableScript = mock(ExecutableScript.class);
|
||||
when(scriptService.executable(any(), any())).thenReturn(executableScript);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
esplugin {
|
||||
description 'Mustache scripting integration for Elasticsearch'
|
||||
classname 'org.elasticsearch.script.mustache.MustachePlugin'
|
||||
hasClientJar = true // For the template query
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
*/
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestDeleteStoredScriptAction;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.DELETE;
|
||||
|
||||
|
@ -38,6 +36,6 @@ public class RestDeleteSearchTemplateAction extends RestDeleteStoredScriptAction
|
|||
|
||||
@Override
|
||||
protected String getScriptLang(RestRequest request) {
|
||||
return Template.DEFAULT_LANG;
|
||||
return "mustache";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
*/
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestGetStoredScriptAction;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||
|
||||
|
@ -40,7 +38,7 @@ public class RestGetSearchTemplateAction extends RestGetStoredScriptAction {
|
|||
|
||||
@Override
|
||||
protected String getScriptLang(RestRequest request) {
|
||||
return Template.DEFAULT_LANG;
|
||||
return "mustache";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,13 +18,11 @@
|
|||
*/
|
||||
package org.elasticsearch.rest.action.search.template;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.admin.cluster.storedscripts.RestPutStoredScriptAction;
|
||||
import org.elasticsearch.script.Template;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
||||
|
@ -40,6 +38,6 @@ public class RestPutSearchTemplateAction extends RestPutStoredScriptAction {
|
|||
|
||||
@Override
|
||||
protected String getScriptLang(RestRequest request) {
|
||||
return Template.DEFAULT_LANG;
|
||||
return "mustache";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.elasticsearch.rest.action.search.template.RestPutSearchTemplateAction
|
|||
import org.elasticsearch.rest.action.search.template.RestRenderSearchTemplateAction;
|
||||
import org.elasticsearch.rest.action.search.template.RestSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptEngineService;
|
||||
import org.elasticsearch.search.SearchModule;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -54,6 +55,10 @@ public class MustachePlugin extends Plugin implements ScriptPlugin, ActionPlugin
|
|||
new ActionHandler<>(MultiSearchTemplateAction.INSTANCE, TransportMultiSearchTemplateAction.class));
|
||||
}
|
||||
|
||||
public void onModule(SearchModule module) {
|
||||
module.registerQuery(TemplateQueryBuilder::new, TemplateQueryBuilder::fromXContent, TemplateQueryBuilder.QUERY_NAME_FIELD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends RestHandler>> getRestHandlers() {
|
||||
return Arrays.asList(RestSearchTemplateAction.class, RestMultiSearchTemplateAction.class, RestGetSearchTemplateAction.class,
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.elasticsearch.index.query;
|
||||
package org.elasticsearch.script.mustache;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
|
@ -27,12 +27,21 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
|||
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.index.query.AbstractQueryBuilder;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.QueryRewriteContext;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
|
@ -45,20 +54,25 @@ public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuil
|
|||
public static final ParseField QUERY_NAME_FIELD = new ParseField(NAME);
|
||||
|
||||
/** Template to fill. */
|
||||
private final Template template;
|
||||
private final Script template;
|
||||
|
||||
/**
|
||||
* @param template
|
||||
* the template to use for that query.
|
||||
* */
|
||||
public TemplateQueryBuilder(Template template) {
|
||||
public TemplateQueryBuilder(String template, ScriptService.ScriptType scriptType, Map<String, Object> params) {
|
||||
this.template = new Script(template, scriptType, "mustache", params);
|
||||
}
|
||||
|
||||
public TemplateQueryBuilder(String template, ScriptService.ScriptType scriptType, Map<String, Object> params, XContentType ct) {
|
||||
this.template = new Script(template, scriptType, "mustache", params, ct);
|
||||
}
|
||||
|
||||
// for tests, so that mock script can be used:
|
||||
TemplateQueryBuilder(Script template) {
|
||||
if (template == null) {
|
||||
throw new IllegalArgumentException("query template cannot be null");
|
||||
}
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public Template template() {
|
||||
public Script template() {
|
||||
return template;
|
||||
}
|
||||
|
||||
|
@ -67,7 +81,7 @@ public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuil
|
|||
*/
|
||||
public TemplateQueryBuilder(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
template = new Template(in);
|
||||
template = new Script(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -125,7 +139,7 @@ public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuil
|
|||
*/
|
||||
public static Optional<TemplateQueryBuilder> fromXContent(QueryParseContext parseContext) throws IOException {
|
||||
XContentParser parser = parseContext.parser();
|
||||
Template template = Template.parse(parser, parseContext.getParseFieldMatcher());
|
||||
Script template = Script.parse(parser, parseContext.getParseFieldMatcher(), "mustache");
|
||||
return Optional.of(new TemplateQueryBuilder(template));
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ import org.elasticsearch.index.fielddata.IndexFieldDataService;
|
|||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.script.mustache.TemplateQueryBuilder;
|
||||
import org.elasticsearch.index.query.functionscore.ScoreFunctionParser;
|
||||
import org.elasticsearch.index.shard.ShardId;
|
||||
import org.elasticsearch.index.similarity.SimilarityService;
|
||||
|
|
|
@ -30,13 +30,11 @@ import org.elasticsearch.common.ParsingException;
|
|||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.TemplateQueryBuilder;
|
||||
import org.elasticsearch.script.mustache.TemplateQueryBuilder;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.rest.action.search.template.RestSearchTemplateAction;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
@ -95,8 +93,7 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("template", "all");
|
||||
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(new Template("{\"match_{{template}}\": {}}\"", ScriptType.INLINE, null,
|
||||
null, vars));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("{\"match_{{template}}\": {}}\"", ScriptType.INLINE,vars);
|
||||
SearchResponse sr = client().prepareSearch().setQuery(builder)
|
||||
.execute().actionGet();
|
||||
assertHitCount(sr, 2);
|
||||
|
@ -108,9 +105,8 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
SearchResponse sr = client().prepareSearch()
|
||||
.setSource(
|
||||
new SearchSourceBuilder().size(0).query(
|
||||
QueryBuilders.templateQuery(new Template("{ \"match_{{template}}\": {} }",
|
||||
ScriptType.INLINE, null, null, params)))).execute()
|
||||
.actionGet();
|
||||
new TemplateQueryBuilder("{ \"match_{{template}}\": {} }", ScriptType.INLINE, params)))
|
||||
.get();
|
||||
assertNoFailures(sr);
|
||||
assertThat(sr.getHits().hits().length, equalTo(0));
|
||||
}
|
||||
|
@ -118,8 +114,7 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
public void testTemplateWOReplacementInBody() throws IOException {
|
||||
Map<String, Object> vars = new HashMap<>();
|
||||
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(new Template(
|
||||
"{\"match_all\": {}}\"", ScriptType.INLINE, null, null, vars));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("{\"match_all\": {}}\"", ScriptType.INLINE, vars);
|
||||
SearchResponse sr = client().prepareSearch().setQuery(builder)
|
||||
.execute().actionGet();
|
||||
assertHitCount(sr, 2);
|
||||
|
@ -129,8 +124,7 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("template", "all");
|
||||
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(new Template(
|
||||
"storedTemplate", ScriptService.ScriptType.FILE, null, null, vars));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("storedTemplate", ScriptService.ScriptType.FILE, vars);
|
||||
SearchResponse sr = client().prepareSearch().setQuery(builder)
|
||||
.execute().actionGet();
|
||||
assertHitCount(sr, 2);
|
||||
|
@ -139,7 +133,7 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
public void testRawFSTemplate() throws IOException {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("template", "all");
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(new Template("storedTemplate", ScriptType.FILE, null, null, params));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("storedTemplate", ScriptType.FILE, params);
|
||||
SearchResponse sr = client().prepareSearch().setQuery(builder).get();
|
||||
assertHitCount(sr, 2);
|
||||
}
|
||||
|
@ -411,8 +405,7 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("fieldParam", "bar");
|
||||
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(new Template(
|
||||
"3", ScriptService.ScriptType.STORED, null, null, vars));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("3", ScriptService.ScriptType.STORED, vars);
|
||||
SearchResponse sr = client().prepareSearch().setQuery(builder)
|
||||
.execute().actionGet();
|
||||
assertHitCount(sr, 1);
|
||||
|
@ -420,11 +413,11 @@ public class TemplateQueryTests extends ESIntegTestCase {
|
|||
// "{\"template\": {\"id\": \"3\",\"params\" : {\"fieldParam\" : \"foo\"}}}";
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("fieldParam", "foo");
|
||||
TemplateQueryBuilder templateQuery = new TemplateQueryBuilder(new Template("3", ScriptType.STORED, null, null, params));
|
||||
TemplateQueryBuilder templateQuery = new TemplateQueryBuilder("3", ScriptType.STORED, params);
|
||||
sr = client().prepareSearch().setQuery(templateQuery).get();
|
||||
assertHitCount(sr, 4);
|
||||
|
||||
templateQuery = new TemplateQueryBuilder(new Template("/mustache/3", ScriptType.STORED, null, null, params));
|
||||
templateQuery = new TemplateQueryBuilder("/mustache/3", ScriptType.STORED, params);
|
||||
sr = client().prepareSearch().setQuery(templateQuery).get();
|
||||
assertHitCount(sr, 4);
|
||||
}
|
||||
|
|
|
@ -17,21 +17,29 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.index.query;
|
||||
package org.elasticsearch.script.mustache;
|
||||
|
||||
import org.apache.lucene.index.memory.MemoryIndex;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.script.Script.ScriptParseException;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.MatchQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.test.AbstractQueryTestCase;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -43,9 +51,14 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
*/
|
||||
private QueryBuilder templateBase;
|
||||
|
||||
@Override
|
||||
protected Collection<Class<? extends Plugin>> getPlugins() {
|
||||
return Collections.singleton(MustachePlugin.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
templateBase = RandomQueryBuilder.createQuery(random());
|
||||
templateBase = new MatchQueryBuilder("field", "some values");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,7 +68,7 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
|
||||
@Override
|
||||
protected TemplateQueryBuilder doCreateTestQueryBuilder() {
|
||||
return new TemplateQueryBuilder(new Template(templateBase.toString(), ScriptType.INLINE, "mockscript", null, null));
|
||||
return new TemplateQueryBuilder(new Script(templateBase.toString(), ScriptType.INLINE, "mockscript", null, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,7 +77,7 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
}
|
||||
|
||||
public void testIllegalArgument() {
|
||||
expectThrows(IllegalArgumentException.class, () -> new TemplateQueryBuilder((Template) null));
|
||||
expectThrows(IllegalArgumentException.class, () -> new TemplateQueryBuilder((Script) null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +92,7 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
try {
|
||||
parseQuery(queryAsString);
|
||||
fail("ScriptParseException expected.");
|
||||
} catch (ScriptParseException e) {
|
||||
} catch (ElasticsearchParseException e) {
|
||||
assertTrue(e.getMessage().contains("bogusField"));
|
||||
}
|
||||
}
|
||||
|
@ -87,8 +100,7 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
public void testJSONGeneration() throws IOException {
|
||||
Map<String, Object> vars = new HashMap<>();
|
||||
vars.put("template", "filled");
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder(
|
||||
new Template("I am a $template string", ScriptType.INLINE, null, null, vars));
|
||||
TemplateQueryBuilder builder = new TemplateQueryBuilder("I am a $template string", ScriptType.INLINE, vars);
|
||||
XContentBuilder content = XContentFactory.jsonBuilder();
|
||||
content.startObject();
|
||||
builder.doXContent(content, null);
|
||||
|
@ -103,8 +115,7 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
String query = "{\"template\": {\"inline\": \"{\\\"match_{{template}}\\\": {}}\\\"\",\"params\" : {\"template\" : \"all\"}}}";
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("template", "all");
|
||||
QueryBuilder expectedBuilder = new TemplateQueryBuilder(new Template(expectedTemplateString, ScriptType.INLINE, null, null,
|
||||
params));
|
||||
QueryBuilder expectedBuilder = new TemplateQueryBuilder(expectedTemplateString, ScriptType.INLINE, params);
|
||||
assertParsedQuery(query, expectedBuilder);
|
||||
}
|
||||
|
||||
|
@ -113,16 +124,15 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
String query = "{\"template\": {\"inline\": {\"match_{{template}}\": {}},\"params\" : {\"template\" : \"all\"}}}";
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("template", "all");
|
||||
QueryBuilder expectedBuilder = new TemplateQueryBuilder(new Template(expectedTemplateString, ScriptType.INLINE, null,
|
||||
XContentType.JSON, params));
|
||||
QueryBuilder expectedBuilder = new TemplateQueryBuilder(expectedTemplateString, ScriptType.INLINE, params, XContentType.JSON);
|
||||
assertParsedQuery(query, expectedBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testMustRewrite() throws IOException {
|
||||
String query = "{ \"match_all\" : {}}";
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Template(query, ScriptType.INLINE, "mockscript",
|
||||
XContentType.JSON, Collections.emptyMap()));
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Script(query, ScriptType.INLINE, "mockscript",
|
||||
Collections.emptyMap(), XContentType.JSON));
|
||||
try {
|
||||
builder.toQuery(createShardContext());
|
||||
fail();
|
||||
|
@ -134,24 +144,24 @@ public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQue
|
|||
|
||||
public void testRewriteWithInnerName() throws IOException {
|
||||
final String query = "{ \"match_all\" : {\"_name\" : \"foobar\"}}";
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Template(query, ScriptType.INLINE, "mockscript",
|
||||
XContentType.JSON, Collections.emptyMap()));
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Script(query, ScriptType.INLINE, "mockscript",
|
||||
Collections.emptyMap(), XContentType.JSON));
|
||||
assertEquals(new MatchAllQueryBuilder().queryName("foobar"), builder.rewrite(createShardContext()));
|
||||
|
||||
builder = new TemplateQueryBuilder(new Template(query, ScriptType.INLINE, "mockscript",
|
||||
XContentType.JSON, Collections.emptyMap())).queryName("outer");
|
||||
builder = new TemplateQueryBuilder(new Script(query, ScriptType.INLINE, "mockscript",
|
||||
Collections.emptyMap(), XContentType.JSON)).queryName("outer");
|
||||
assertEquals(new BoolQueryBuilder().must(new MatchAllQueryBuilder().queryName("foobar")).queryName("outer"),
|
||||
builder.rewrite(createShardContext()));
|
||||
}
|
||||
|
||||
public void testRewriteWithInnerBoost() throws IOException {
|
||||
final TermQueryBuilder query = new TermQueryBuilder("foo", "bar").boost(2);
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Template(query.toString(), ScriptType.INLINE, "mockscript",
|
||||
XContentType.JSON, Collections.emptyMap()));
|
||||
QueryBuilder builder = new TemplateQueryBuilder(new Script(query.toString(), ScriptType.INLINE, "mockscript",
|
||||
Collections.emptyMap(), XContentType.JSON));
|
||||
assertEquals(query, builder.rewrite(createShardContext()));
|
||||
|
||||
builder = new TemplateQueryBuilder(new Template(query.toString(), ScriptType.INLINE, "mockscript",
|
||||
XContentType.JSON, Collections.emptyMap())).boost(3);
|
||||
builder = new TemplateQueryBuilder(new Script(query.toString(), ScriptType.INLINE, "mockscript",
|
||||
Collections.emptyMap(), XContentType.JSON)).boost(3);
|
||||
assertEquals(new BoolQueryBuilder().must(query).boost(3), builder.rewrite(createShardContext()));
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ public class PercolateQueryBuilderTests extends AbstractQueryTestCase<PercolateQ
|
|||
try {
|
||||
parseQuery(testQuery);
|
||||
fail("some parsing exception expected for query: " + testQuery);
|
||||
} catch (ParsingException | Script.ScriptParseException | ElasticsearchParseException e) {
|
||||
} catch (ParsingException | ElasticsearchParseException e) {
|
||||
// different kinds of exception wordings depending on location
|
||||
// of mutation, so no simple asserts possible here
|
||||
} catch (JsonParseException e) {
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
package org.elasticsearch.index.reindex;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.cluster.service.ClusterService;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
|
@ -29,15 +31,18 @@ import org.elasticsearch.rest.RestChannel;
|
|||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||
import static org.elasticsearch.script.Script.ScriptField;
|
||||
|
||||
public class RestUpdateByQueryAction extends AbstractBulkByQueryRestHandler<UpdateByQueryRequest, UpdateByQueryAction> {
|
||||
|
||||
|
@ -67,11 +72,65 @@ public class RestUpdateByQueryAction extends AbstractBulkByQueryRestHandler<Upda
|
|||
|
||||
Map<String, Consumer<Object>> consumers = new HashMap<>();
|
||||
consumers.put("conflicts", o -> internal.setConflicts((String) o));
|
||||
consumers.put("script", o -> internal.setScript(Script.parse((Map<String, Object>)o, false, parseFieldMatcher)));
|
||||
consumers.put("script", o -> internal.setScript(parseScript((Map<String, Object>)o, parseFieldMatcher)));
|
||||
|
||||
parseInternalRequest(internal, request, consumers);
|
||||
|
||||
internal.setPipeline(request.param("pipeline"));
|
||||
return internal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Script parseScript(Map<String, Object> config, ParseFieldMatcher parseFieldMatcher) {
|
||||
String script = null;
|
||||
ScriptService.ScriptType type = null;
|
||||
String lang = null;
|
||||
Map<String, Object> params = null;
|
||||
for (Iterator<Map.Entry<String, Object>> itr = config.entrySet().iterator(); itr.hasNext();) {
|
||||
Map.Entry<String, Object> entry = itr.next();
|
||||
String parameterName = entry.getKey();
|
||||
Object parameterValue = entry.getValue();
|
||||
if (parseFieldMatcher.match(parameterName, ScriptField.LANG)) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
lang = (String) parameterValue;
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptField.PARAMS)) {
|
||||
if (parameterValue instanceof Map || parameterValue == null) {
|
||||
params = (Map<String, Object>) parameterValue;
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptService.ScriptType.INLINE.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptService.ScriptType.INLINE;
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptService.ScriptType.FILE.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptService.ScriptType.FILE;
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
} else if (parseFieldMatcher.match(parameterName, ScriptService.ScriptType.STORED.getParseField())) {
|
||||
if (parameterValue instanceof String || parameterValue == null) {
|
||||
script = (String) parameterValue;
|
||||
type = ScriptService.ScriptType.STORED;
|
||||
} else {
|
||||
throw new ElasticsearchParseException("Value must be of type String: [" + parameterName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (script == null) {
|
||||
throw new ElasticsearchParseException("expected one of [{}], [{}] or [{}] fields, but found none",
|
||||
ScriptService.ScriptType.INLINE.getParseField().getPreferredName(), ScriptService.ScriptType.FILE.getParseField()
|
||||
.getPreferredName(), ScriptService.ScriptType.STORED.getParseField().getPreferredName());
|
||||
}
|
||||
assert type != null : "if script is not null, type should definitely not be null";
|
||||
return new Script(script, type, lang, params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@ import org.elasticsearch.plugins.MapperPlugin;
|
|||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.plugins.PluginsService;
|
||||
import org.elasticsearch.plugins.SearchPlugin;
|
||||
import org.elasticsearch.script.Script.ScriptParseException;
|
||||
import org.elasticsearch.script.ScriptModule;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.SearchModule;
|
||||
|
@ -304,7 +303,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
|
|||
try {
|
||||
parseQuery(testQuery);
|
||||
fail("some parsing exception expected for query: " + testQuery);
|
||||
} catch (ParsingException | ScriptParseException | ElasticsearchParseException e) {
|
||||
} catch (ParsingException | ElasticsearchParseException e) {
|
||||
// different kinds of exception wordings depending on location
|
||||
// of mutation, so no simple asserts possible here
|
||||
} catch (JsonParseException e) {
|
||||
|
|
Loading…
Reference in New Issue