Test: Convert test script engine impls to use MockScriptEngine (#24854)

This commit cleans up tests which currently use custom script engine
implementations, converting them to use a MockScriptEngine with script
functions provided by the tests. It also creates a common set of metric
scripts which were copied across a couple metric agg tests.
This commit is contained in:
Ryan Ernst 2017-05-23 20:34:12 -07:00 committed by GitHub
parent 2e570fc6fa
commit bf49d37ab3
9 changed files with 300 additions and 931 deletions

View File

@ -23,6 +23,7 @@ import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
@ -46,7 +47,6 @@ import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
//TODO: this needs to be a base test class, and all scripting engines extend it
public class ScriptServiceTests extends ESTestCase {
private ScriptEngine scriptEngine;
@ -63,15 +63,18 @@ public class ScriptServiceTests extends ESTestCase {
.put(Environment.PATH_CONF_SETTING.getKey(), genericConfigFolder)
.put(ScriptService.SCRIPT_MAX_COMPILATIONS_PER_MINUTE.getKey(), 10000)
.build();
scriptEngine = new TestEngine();
TestEngine defaultScriptServiceEngine = new TestEngine(Script.DEFAULT_SCRIPT_LANG) {};
//randomly register custom script contexts
int randomInt = randomIntBetween(0, 3);
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
for (int i = 0; i < 20; ++i) {
scripts.put(i + "+" + i, p -> null); // only care about compilation, not execution
}
scripts.put("script", p -> null);
scriptEngine = new MockScriptEngine(Script.DEFAULT_SCRIPT_LANG, scripts);
//prevent duplicates using map
contexts = new HashMap<>(ScriptContext.BUILTINS);
engines = new HashMap<>();
engines.put(scriptEngine.getType(), scriptEngine);
engines.put(defaultScriptServiceEngine.getType(), defaultScriptServiceEngine);
engines.put("test", new MockScriptEngine("test", scripts));
logger.info("--> setup script service");
}
@ -81,7 +84,7 @@ public class ScriptServiceTests extends ESTestCase {
@Override
StoredScriptSource getScriptFromClusterState(String id, String lang) {
//mock the script that gets retrieved from an index
return new StoredScriptSource(lang, "100", Collections.emptyMap());
return new StoredScriptSource(lang, "1+1", Collections.emptyMap());
}
};
}
@ -215,10 +218,10 @@ public class ScriptServiceTests extends ESTestCase {
public void testMultipleCompilationsCountedInCompilationStats() throws IOException {
buildScriptService(Settings.EMPTY);
int numberOfCompilations = randomIntBetween(1, 1024);
int numberOfCompilations = randomIntBetween(1, 20);
for (int i = 0; i < numberOfCompilations; i++) {
scriptService
.compile(new Script(ScriptType.INLINE, "test", i + " + " + i, Collections.emptyMap()), randomFrom(contexts.values()));
.compile(new Script(ScriptType.INLINE, "test", i + "+" + i, Collections.emptyMap()), randomFrom(contexts.values()));
}
assertEquals(numberOfCompilations, scriptService.stats().getCompilations());
}
@ -253,7 +256,7 @@ public class ScriptServiceTests extends ESTestCase {
Settings.Builder builder = Settings.builder();
buildScriptService(builder.build());
CompiledScript script = scriptService.compile(
new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "1 + 1", Collections.emptyMap()), randomFrom(contexts.values()));
new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "1+1", Collections.emptyMap()), randomFrom(contexts.values()));
assertEquals(script.lang(), Script.DEFAULT_SCRIPT_LANG);
}
@ -314,43 +317,4 @@ public class ScriptServiceTests extends ESTestCase {
);
}
public static class TestEngine implements ScriptEngine {
public static final String NAME = "test";
private final String name;
public TestEngine() {
this(NAME);
}
public TestEngine(String name) {
this.name = name;
}
@Override
public String getType() {
return name;
}
@Override
public Object compile(String scriptName, String scriptText, Map<String, String> params) {
return "compiled_" + scriptText;
}
@Override
public ExecutableScript executable(final CompiledScript compiledScript, @Nullable Map<String, Object> vars) {
return null;
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, @Nullable Map<String, Object> vars) {
return null;
}
@Override
public void close() {
}
}
}

View File

@ -18,37 +18,24 @@
*/
package org.elasticsearch.search.aggregations.metrics;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.Scorer;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.avg.Avg;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.lookup.LeafSearchLookup;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@ -57,6 +44,11 @@ import static org.elasticsearch.search.aggregations.AggregationBuilders.filter;
import static org.elasticsearch.search.aggregations.AggregationBuilders.global;
import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram;
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.METRIC_SCRIPT_ENGINE;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_FIELD_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_FIELD_PARAMS_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_VALUES_FIELD_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_SCRIPT;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
@ -68,9 +60,7 @@ public class AvgIT extends AbstractNumericTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(
ExtractFieldScriptPlugin.class,
FieldValueScriptPlugin.class);
return Collections.singleton(MetricAggScriptPlugin.class);
}
@Override
@ -168,7 +158,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg").field("value")
.script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap())))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -185,7 +175,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg").field("value")
.script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params)))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -229,7 +219,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg").field("values")
.script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap())))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -246,7 +236,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg").field("values")
.script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params)))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -262,7 +252,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg")
.script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "value", Collections.emptyMap())))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -275,11 +265,13 @@ public class AvgIT extends AbstractNumericTestCase {
@Override
public void testScriptSingleValuedWithParams() throws Exception {
Map<String, Object> params = Collections.singletonMap("inc", 1);
Map<String, Object> params = new HashMap<>();
params.put("inc", 1);
params.put("field", "value");
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg")
.script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "value", params)))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_FIELD_PARAMS_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -295,7 +287,7 @@ public class AvgIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg")
.script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "values", Collections.emptyMap())))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_VALUES_FIELD_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -308,11 +300,13 @@ public class AvgIT extends AbstractNumericTestCase {
@Override
public void testScriptMultiValuedWithParams() throws Exception {
Map<String, Object> params = Collections.singletonMap("inc", 1);
Map<String, Object> params = new HashMap<>();
params.put("inc", 1);
params.put("field", "values");
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(avg("avg")
.script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "values", params)))
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_FIELD_PARAMS_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -373,7 +367,7 @@ public class AvgIT extends AbstractNumericTestCase {
// Test that a request using a script does not get cached
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
.addAggregation(avg("foo").field("d").script(
new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap()))).get();
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap()))).get();
assertSearchResponse(r);
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
@ -391,202 +385,4 @@ public class AvgIT extends AbstractNumericTestCase {
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
.getMissCount(), equalTo(1L));
}
/**
* Mock plugin for the {@link ExtractFieldScriptEngine}
*/
public static class ExtractFieldScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new ExtractFieldScriptEngine();
}
}
/**
* This mock script returns the field that is specified by name in the script body
*/
public static class ExtractFieldScriptEngine implements ScriptEngine {
public static final String NAME = "extract_field";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
final long inc;
if (vars == null || vars.containsKey("inc") == false) {
inc = 0;
} else {
inc = ((Number) vars.get("inc")).longValue();
}
return new SearchScript() {
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new LeafSearchScript() {
@Override
public void setNextVar(String name, Object value) {
}
@Override
public Object run() {
String fieldName = (String) compiledScript.compiled();
List<Long> values = new ArrayList<>();
for (Object v : (List<?>) leafLookup.doc().get(fieldName)) {
values.add(((Number) v).longValue() + inc);
}
return values;
}
@Override
public void setScorer(Scorer scorer) {
}
@Override
public void setSource(Map<String, Object> source) {
}
@Override
public void setDocument(int doc) {
if (leafLookup != null) {
leafLookup.setDocument(doc);
}
}
@Override
public long runAsLong() {
throw new UnsupportedOperationException();
}
@Override
public double runAsDouble() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean needsScores() {
return false;
}
};
}
}
/**
* Mock plugin for the {@link FieldValueScriptEngine}
*/
public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new FieldValueScriptEngine();
}
}
/**
* This mock script returns the field value and adds one month to the returned date
*/
public static class FieldValueScriptEngine implements ScriptEngine {
public static final String NAME = "field_value";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
final long inc;
if (vars == null || vars.containsKey("inc") == false) {
inc = 0;
} else {
inc = ((Number) vars.get("inc")).longValue();
}
return new SearchScript() {
private Map<String, Object> vars = new HashMap<>(2);
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new LeafSearchScript() {
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
throw new UnsupportedOperationException();
}
@Override
public void setScorer(Scorer scorer) {
}
@Override
public void setSource(Map<String, Object> source) {
}
@Override
public void setDocument(int doc) {
if (leafLookup != null) {
leafLookup.setDocument(doc);
}
}
@Override
public long runAsLong() {
return ((Number) vars.get("_value")).longValue() + inc;
}
@Override
public double runAsDouble() {
return ((Number) vars.get("_value")).doubleValue() + inc;
}
};
}
@Override
public boolean needsScores() {
return false;
}
};
}
}
}

View File

@ -0,0 +1,91 @@
/*
* 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.search.aggregations.metrics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.search.lookup.LeafDocLookup;
/**
* Provides a number of dummy scripts for tests.
*
* Each script provided allows for an {@code inc} parameter which will
* be added to each value read from a document.
*/
public class MetricAggScriptPlugin extends MockScriptPlugin {
/** The name of the script engine type this plugin provides. */
public static final String METRIC_SCRIPT_ENGINE = "metric_scripts";
/** Script to take a field name in params and sum the values of the field. */
public static final String SUM_FIELD_PARAMS_SCRIPT = "sum_field_params";
/** Script to sum the values of a field named {@code values}. */
public static final String SUM_VALUES_FIELD_SCRIPT = "sum_values_field";
/** Script to return the value of a field named {@code value}. */
public static final String VALUE_FIELD_SCRIPT = "value_field";
/** Script to return the {@code _value} provided by aggs framework. */
public static final String VALUE_SCRIPT = "_value";
@Override
public String pluginScriptLang() {
return METRIC_SCRIPT_ENGINE;
}
@Override
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
Function<Map<String, Object>, Integer> getInc = vars -> {
if (vars == null || vars.containsKey("inc") == false) {
return 0;
} else {
return ((Number) vars.get("inc")).intValue();
}
};
BiFunction<Map<String, Object>, String, Object> sum = (vars, fieldname) -> {
int inc = getInc.apply(vars);
LeafDocLookup docLookup = (LeafDocLookup) vars.get("doc");
List<Long> values = new ArrayList<>();
for (Object v : docLookup.get(fieldname)) {
values.add(((Number) v).longValue() + inc);
}
return values;
};
scripts.put(SUM_FIELD_PARAMS_SCRIPT, vars -> {
String fieldname = (String) vars.get("field");
return sum.apply(vars, fieldname);
});
scripts.put(SUM_VALUES_FIELD_SCRIPT, vars -> sum.apply(vars, "values"));
scripts.put(VALUE_FIELD_SCRIPT, vars -> sum.apply(vars, "value"));
scripts.put(VALUE_SCRIPT, vars -> {
int inc = getInc.apply(vars);
return ((Number) vars.get("_value")).doubleValue() + inc;
});
return scripts;
}
}

View File

@ -18,37 +18,24 @@
*/
package org.elasticsearch.search.aggregations.metrics;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.Scorer;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.lookup.LeafSearchLookup;
import org.elasticsearch.search.lookup.SearchLookup;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@ -57,6 +44,10 @@ import static org.elasticsearch.search.aggregations.AggregationBuilders.global;
import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram;
import static org.elasticsearch.search.aggregations.AggregationBuilders.sum;
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.METRIC_SCRIPT_ENGINE;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_VALUES_FIELD_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_FIELD_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_SCRIPT;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
@ -67,7 +58,7 @@ public class SumIT extends AbstractNumericTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(ExtractFieldScriptPlugin.class, FieldValueScriptPlugin.class);
return Collections.singleton(MetricAggScriptPlugin.class);
}
@Override
@ -178,7 +169,7 @@ public class SumIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").field("value").script(
new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap())))
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -195,7 +186,7 @@ public class SumIT extends AbstractNumericTestCase {
params.put("increment", 1);
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").field("value").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params)))
.addAggregation(sum("sum").field("value").script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -211,7 +202,7 @@ public class SumIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").script(
new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "value", Collections.emptyMap())))
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.singletonMap("field", "value"))))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -228,7 +219,7 @@ public class SumIT extends AbstractNumericTestCase {
params.put("inc", 1);
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "value", params)))
.addAggregation(sum("sum").script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -244,7 +235,7 @@ public class SumIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").script(
new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "values", Collections.emptyMap())))
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_VALUES_FIELD_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -262,7 +253,7 @@ public class SumIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(
sum("sum").script(new Script(ScriptType.INLINE, ExtractFieldScriptEngine.NAME, "values", params)))
sum("sum").script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_VALUES_FIELD_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -295,7 +286,7 @@ public class SumIT extends AbstractNumericTestCase {
SearchResponse searchResponse = client().prepareSearch("idx")
.setQuery(matchAllQuery())
.addAggregation(sum("sum").field("values").script(
new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap())))
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -311,7 +302,8 @@ public class SumIT extends AbstractNumericTestCase {
Map<String, Object> params = new HashMap<>();
params.put("increment", 1);
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(sum("sum").field("values").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params)))
.addAggregation(sum("sum").field("values")
.script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -372,7 +364,7 @@ public class SumIT extends AbstractNumericTestCase {
// Test that a request using a script does not get cached
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
.addAggregation(sum("foo").field("d").script(
new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", Collections.emptyMap()))).get();
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap()))).get();
assertSearchResponse(r);
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
@ -390,207 +382,4 @@ public class SumIT extends AbstractNumericTestCase {
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
.getMissCount(), equalTo(1L));
}
/**
* Mock plugin for the {@link ExtractFieldScriptEngine}
*/
public static class ExtractFieldScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new ExtractFieldScriptEngine();
}
}
/**
* This mock script returns the field that is specified by name in the
* script body
*/
public static class ExtractFieldScriptEngine implements ScriptEngine {
public static final String NAME = "extract_field";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
final long inc;
if (vars == null || vars.containsKey("inc") == false) {
inc = 0;
} else {
inc = ((Number) vars.get("inc")).longValue();
}
return new SearchScript() {
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new LeafSearchScript() {
@Override
public void setNextVar(String name, Object value) {
}
@Override
public Object run() {
String fieldName = (String) compiledScript.compiled();
List<Long> values = new ArrayList<>();
for (Object v : (List<?>) leafLookup.doc().get(fieldName)) {
values.add(((Number) v).longValue() + inc);
}
return values;
}
@Override
public void setScorer(Scorer scorer) {
}
@Override
public void setSource(Map<String, Object> source) {
}
@Override
public void setDocument(int doc) {
if (leafLookup != null) {
leafLookup.setDocument(doc);
}
}
@Override
public long runAsLong() {
throw new UnsupportedOperationException();
}
@Override
public double runAsDouble() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean needsScores() {
return false;
}
};
}
}
/**
* Mock plugin for the {@link FieldValueScriptEngine}
*/
public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new FieldValueScriptEngine();
}
}
/**
* This mock script returns the field value and adds one to the returned
* value
*/
public static class FieldValueScriptEngine implements ScriptEngine {
public static final String NAME = "field_value";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
final long inc;
if (vars == null || vars.containsKey("inc") == false) {
inc = 0;
} else {
inc = ((Number) vars.get("inc")).longValue();
}
return new SearchScript() {
private Map<String, Object> vars = new HashMap<>(2);
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new LeafSearchScript() {
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
throw new UnsupportedOperationException();
}
@Override
public void setScorer(Scorer scorer) {
}
@Override
public void setSource(Map<String, Object> source) {
}
@Override
public void setDocument(int doc) {
if (leafLookup != null) {
leafLookup.setDocument(doc);
}
}
@Override
public long runAsLong() {
return ((Number) vars.get("_value")).longValue() + inc;
}
@Override
public double runAsDouble() {
return ((Number) vars.get("_value")).doubleValue() + inc;
}
};
}
@Override
public boolean needsScores() {
return false;
}
};
}
}
}

View File

@ -18,36 +18,28 @@
*/
package org.elasticsearch.search.aggregations.metrics;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.Scorer;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.LeafSearchScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.global.Global;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount;
import org.elasticsearch.search.lookup.LeafSearchLookup;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESIntegTestCase;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.search.aggregations.AggregationBuilders.count;
import static org.elasticsearch.search.aggregations.AggregationBuilders.global;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.METRIC_SCRIPT_ENGINE;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_FIELD_PARAMS_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_VALUES_FIELD_SCRIPT;
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_FIELD_SCRIPT;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
@ -75,7 +67,7 @@ public class ValueCountIT extends ESIntegTestCase {
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singletonList(FieldValueScriptPlugin.class);
return Collections.singletonList(MetricAggScriptPlugin.class);
}
public void testUnmapped() throws Exception {
@ -158,7 +150,9 @@ public class ValueCountIT extends ESIntegTestCase {
public void testSingleValuedScript() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(count("count").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "value", Collections.emptyMap()))).execute().actionGet();
.addAggregation(count("count").script(
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -170,7 +164,9 @@ public class ValueCountIT extends ESIntegTestCase {
public void testMultiValuedScript() throws Exception {
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(count("count").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "values", Collections.emptyMap()))).execute().actionGet();
.addAggregation(count("count").script(
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_VALUES_FIELD_SCRIPT, Collections.emptyMap())))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -181,9 +177,10 @@ public class ValueCountIT extends ESIntegTestCase {
}
public void testSingleValuedScriptWithParams() throws Exception {
Map<String, Object> params = Collections.singletonMap("s", "value");
Map<String, Object> params = Collections.singletonMap("field", "value");
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(count("count").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params))).execute().actionGet();
.addAggregation(count("count").script(new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_FIELD_PARAMS_SCRIPT, params)))
.execute().actionGet();
assertHitCount(searchResponse, 10);
@ -194,9 +191,10 @@ public class ValueCountIT extends ESIntegTestCase {
}
public void testMultiValuedScriptWithParams() throws Exception {
Map<String, Object> params = Collections.singletonMap("s", "values");
Map<String, Object> params = Collections.singletonMap("field", "values");
SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery())
.addAggregation(count("count").script(new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "", params))).execute().actionGet();
.addAggregation(count("count").script(
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, SUM_FIELD_PARAMS_SCRIPT, params))).execute().actionGet();
assertHitCount(searchResponse, 10);
@ -226,7 +224,7 @@ public class ValueCountIT extends ESIntegTestCase {
// Test that a request using a script does not get cached
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
.addAggregation(count("foo").field("d").script(
new Script(ScriptType.INLINE, FieldValueScriptEngine.NAME, "value", Collections.emptyMap())))
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap())))
.get();
assertSearchResponse(r);
@ -245,104 +243,4 @@ public class ValueCountIT extends ESIntegTestCase {
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
.getMissCount(), equalTo(1L));
}
/**
* Mock plugin for the {@link FieldValueScriptEngine}
*/
public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new FieldValueScriptEngine();
}
}
/**
* This mock script returns the field value. If the parameter map contains a parameter "s", the corresponding is used as field name.
*/
public static class FieldValueScriptEngine implements ScriptEngine {
public static final String NAME = "field_value";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
throw new UnsupportedOperationException();
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
final String fieldNameParam;
if (vars == null || vars.containsKey("s") == false) {
fieldNameParam = null;
} else {
fieldNameParam = (String) vars.get("s");
}
return new SearchScript() {
private Map<String, Object> vars = new HashMap<>(2);
@Override
public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException {
final LeafSearchLookup leafLookup = lookup.getLeafSearchLookup(context);
return new LeafSearchScript() {
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
String fieldName = (fieldNameParam != null) ? fieldNameParam : (String) compiledScript.compiled();
return leafLookup.doc().get(fieldName);
}
@Override
public void setScorer(Scorer scorer) {
}
@Override
public void setSource(Map<String, Object> source) {
}
@Override
public void setDocument(int doc) {
if (leafLookup != null) {
leafLookup.setDocument(doc);
}
}
@Override
public long runAsLong() {
throw new UnsupportedOperationException();
}
@Override
public double runAsDouble() {
throw new UnsupportedOperationException();
}
};
}
@Override
public boolean needsScores() {
return false;
}
};
}
}
}

View File

@ -50,13 +50,10 @@ import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptServiceTests.TestEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.test.ESTestCase;
@ -67,6 +64,8 @@ import org.junit.BeforeClass;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import static java.util.Collections.emptyList;
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
@ -86,13 +85,9 @@ public abstract class AbstractSortTestCase<T extends SortBuilder<T>> extends EST
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString())
.put(Environment.PATH_CONF_SETTING.getKey(), genericConfigFolder)
.build();
ScriptEngine engine = new TestEngine();
scriptService = new ScriptService(baseSettings, Collections.singletonMap(engine.getType(), engine), ScriptContext.BUILTINS) {
@Override
public CompiledScript compile(Script script, ScriptContext scriptContext) {
return new CompiledScript(ScriptType.INLINE, "mockName", "test", script);
}
};
Map<String, Function<Map<String, Object>, Object>> scripts = Collections.singletonMap("dummy", p -> null);
ScriptEngine engine = new MockScriptEngine(MockScriptEngine.NAME, scripts);
scriptService = new ScriptService(baseSettings, Collections.singletonMap(engine.getType(), engine), ScriptContext.BUILTINS);
SearchModule searchModule = new SearchModule(Settings.EMPTY, false, emptyList());
namedWriteableRegistry = new NamedWriteableRegistry(searchModule.getNamedWriteables());

View File

@ -43,7 +43,7 @@ public class ScriptSortBuilderTests extends AbstractSortTestCase<ScriptSortBuild
public static ScriptSortBuilder randomScriptSortBuilder() {
ScriptSortType type = randomBoolean() ? ScriptSortType.NUMBER : ScriptSortType.STRING;
ScriptSortBuilder builder = new ScriptSortBuilder(mockScript(randomAlphaOfLengthBetween(5, 10)),
ScriptSortBuilder builder = new ScriptSortBuilder(mockScript("dummy"),
type);
if (randomBoolean()) {
builder.order(randomFrom(SortOrder.values()));

View File

@ -19,6 +19,19 @@
package org.elasticsearch.update;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.elasticsearch.ElasticsearchTimeoutException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestValidationException;
@ -37,30 +50,12 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.MergePolicyConfig;
import org.elasticsearch.index.engine.DocumentMissingException;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.lookup.SearchLookup;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertThrows;
@ -71,247 +66,76 @@ import static org.hamcrest.Matchers.nullValue;
public class UpdateIT extends ESIntegTestCase {
public static class PutFieldValuesScriptPlugin extends Plugin implements ScriptPlugin {
private static final String UPDATE_SCRIPTS = "update_scripts";
private static final String PUT_VALUES_SCRIPT = "put_values";
private static final String FIELD_INC_SCRIPT = "field_inc";
private static final String UPSERT_SCRIPT = "scripted_upsert";
private static final String EXTRACT_CTX_SCRIPT = "extract_ctx";
public static class UpdateScriptsPlugin extends MockScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new PutFieldValuesScriptEngine();
public String pluginScriptLang() {
return UPDATE_SCRIPTS;
}
}
public static class PutFieldValuesScriptEngine implements ScriptEngine {
public static final String NAME = "put_values";
@Override
public void close() throws IOException {
}
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put(PUT_VALUES_SCRIPT, vars -> {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
@Override
public String getType() {
return NAME;
}
Map<String, Object> params = new HashMap<>((Map<String, Object>) vars.get("params"));
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> originalParams) {
return new ExecutableScript() {
Map<String, Object> vars = new HashMap<>();
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
Map<String, Object> newCtx = (Map<String, Object>) params.remove("_ctx");
if (newCtx != null) {
assertFalse(newCtx.containsKey("_source"));
ctx.putAll(newCtx);
}
@Override
public Object run() {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
source.putAll(params);
Map<String, Object> params = new HashMap<>(originalParams);
return ctx;
});
scripts.put(FIELD_INC_SCRIPT, vars -> {
Map<String, Object> params = (Map<String, Object>) vars.get("params");
String fieldname = (String) vars.get("field");
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Number currentValue = (Number) source.get(fieldname);
Number inc = (Number) params.getOrDefault("inc", 1);
source.put(fieldname, currentValue.longValue() + inc.longValue());
return ctx;
});
scripts.put(UPSERT_SCRIPT, vars -> {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Number payment = (Number) vars.get("payment");
Number oldBalance = (Number) source.get("balance");
int deduction = "create".equals(ctx.get("op")) ? payment.intValue() / 2 : payment.intValue();
source.put("balance", oldBalance.intValue() - deduction);
return ctx;
});
scripts.put(EXTRACT_CTX_SCRIPT, vars -> {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> newCtx = (Map<String, Object>) params.remove("_ctx");
if (newCtx != null) {
assertFalse(newCtx.containsKey("_source"));
ctx.putAll(newCtx);
}
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Map<String, Object> ctxWithoutSource = new HashMap<>(ctx);
ctxWithoutSource.remove("_source");
source.put("update_context", ctxWithoutSource);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
source.putAll(params);
return ctx;
}
};
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
throw new UnsupportedOperationException();
}
}
public static class FieldIncrementScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new FieldIncrementScriptEngine();
}
}
public static class FieldIncrementScriptEngine implements ScriptEngine {
public static final String NAME = "field_inc";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return scriptSource;
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
final String field = (String) compiledScript.compiled();
return new ExecutableScript() {
Map<String, Object> vars = new HashMap<>();
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Number currentValue = (Number) source.get(field);
Number inc = params == null ? 1L : (Number) params.getOrDefault("inc", 1);
source.put(field, currentValue.longValue() + inc.longValue());
return ctx;
}
};
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
throw new UnsupportedOperationException();
}
}
public static class ScriptedUpsertScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new ScriptedUpsertScriptEngine();
}
}
public static class ScriptedUpsertScriptEngine implements ScriptEngine {
public static final String NAME = "scripted_upsert";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
return new ExecutableScript() {
Map<String, Object> vars = new HashMap<>();
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Number payment = (Number) params.get("payment");
Number oldBalance = (Number) source.get("balance");
int deduction = "create".equals(ctx.get("op")) ? payment.intValue() / 2 : payment.intValue();
source.put("balance", oldBalance.intValue() - deduction);
return ctx;
}
};
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
throw new UnsupportedOperationException();
}
}
public static class ExtractContextInSourceScriptPlugin extends Plugin implements ScriptPlugin {
@Override
public ScriptEngine getScriptEngine(Settings settings) {
return new ExtractContextInSourceScriptEngine();
}
}
public static class ExtractContextInSourceScriptEngine implements ScriptEngine {
public static final String NAME = "extract_ctx";
@Override
public void close() throws IOException {
}
@Override
public String getType() {
return NAME;
}
@Override
public Object compile(String scriptName, String scriptSource, Map<String, String> params) {
return new Object(); // unused
}
@Override
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> params) {
return new ExecutableScript() {
Map<String, Object> vars = new HashMap<>();
@Override
public void setNextVar(String name, Object value) {
vars.put(name, value);
}
@Override
public Object run() {
Map<String, Object> ctx = (Map<String, Object>) vars.get("ctx");
assertNotNull(ctx);
Map<String, Object> source = (Map<String, Object>) ctx.get("_source");
Map<String, Object> ctxWithoutSource = new HashMap<>(ctx);
ctxWithoutSource.remove("_source");
source.put("update_context", ctxWithoutSource);
return ctx;
}
};
}
@Override
public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map<String, Object> vars) {
throw new UnsupportedOperationException();
return ctx;
});
return scripts;
}
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(
PutFieldValuesScriptPlugin.class,
FieldIncrementScriptPlugin.class,
ScriptedUpsertScriptPlugin.class,
ExtractContextInSourceScriptPlugin.class,
InternalSettingsPlugin.class
);
return Arrays.asList(UpdateScriptsPlugin.class, InternalSettingsPlugin.class);
}
private void createTestIndex() throws Exception {
@ -323,10 +147,11 @@ public class UpdateIT extends ESIntegTestCase {
public void testUpsert() throws Exception {
createTestIndex();
ensureGreen();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
UpdateResponse updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.execute().actionGet();
assertEquals(DocWriteResponse.Result.CREATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -338,7 +163,7 @@ public class UpdateIT extends ESIntegTestCase {
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.execute().actionGet();
assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -367,7 +192,7 @@ public class UpdateIT extends ESIntegTestCase {
UpdateResponse updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("balance", openingBalance).endObject())
.setScriptedUpsert(true)
.setScript(new Script(ScriptType.INLINE, "scripted_upsert", "", params))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, UPSERT_SCRIPT, params))
.execute().actionGet();
assertEquals(DocWriteResponse.Result.CREATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -381,7 +206,7 @@ public class UpdateIT extends ESIntegTestCase {
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("balance", openingBalance).endObject())
.setScriptedUpsert(true)
.setScript(new Script(ScriptType.INLINE, "scripted_upsert", "", params))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, UPSERT_SCRIPT, params))
.execute().actionGet();
assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -425,7 +250,7 @@ public class UpdateIT extends ESIntegTestCase {
UpdateResponse updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("extra", "foo")))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, PUT_VALUES_SCRIPT, Collections.singletonMap("extra", "foo")))
.setFetchSource(true)
.execute().actionGet();
@ -437,7 +262,7 @@ public class UpdateIT extends ESIntegTestCase {
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("extra", "foo")))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, PUT_VALUES_SCRIPT, Collections.singletonMap("extra", "foo")))
.setFields("_source")
.execute().actionGet();
@ -451,7 +276,7 @@ public class UpdateIT extends ESIntegTestCase {
public void testIndexAutoCreation() throws Exception {
UpdateResponse updateResponse = client().prepareUpdate("test", "type1", "1")
.setUpsert(XContentFactory.jsonBuilder().startObject().field("bar", "baz").endObject())
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("extra", "foo")))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, PUT_VALUES_SCRIPT, Collections.singletonMap("extra", "foo")))
.setFetchSource(true)
.execute().actionGet();
@ -466,9 +291,9 @@ public class UpdateIT extends ESIntegTestCase {
createTestIndex();
ensureGreen();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
try {
client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap())).execute().actionGet();
client().prepareUpdate(indexOrAlias(), "type1", "1").setScript(fieldIncScript).execute().actionGet();
fail();
} catch (DocumentMissingException e) {
// all is well
@ -477,7 +302,7 @@ public class UpdateIT extends ESIntegTestCase {
client().prepareIndex("test", "type1", "1").setSource("field", 1).execute().actionGet();
UpdateResponse updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap())).execute().actionGet();
.setScript(fieldIncScript).execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(2L));
assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -489,8 +314,9 @@ public class UpdateIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>();
params.put("inc", 3);
params.put("field", "field");
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", params)).execute().actionGet();
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, params)).execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(3L));
assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -502,7 +328,8 @@ public class UpdateIT extends ESIntegTestCase {
// check noop
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("_ctx", Collections.singletonMap("op", "none")))).execute().actionGet();
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, PUT_VALUES_SCRIPT,
Collections.singletonMap("_ctx", Collections.singletonMap("op", "none")))).execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(3L));
assertEquals(DocWriteResponse.Result.NOOP, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -514,7 +341,8 @@ public class UpdateIT extends ESIntegTestCase {
// check delete
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "put_values", "", Collections.singletonMap("_ctx", Collections.singletonMap("op", "delete")))).execute().actionGet();
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, PUT_VALUES_SCRIPT,
Collections.singletonMap("_ctx", Collections.singletonMap("op", "delete")))).execute().actionGet();
assertThat(updateResponse.getVersion(), equalTo(4L));
assertEquals(DocWriteResponse.Result.DELETED, updateResponse.getResult());
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -527,7 +355,7 @@ public class UpdateIT extends ESIntegTestCase {
// check fields parameter
client().prepareIndex("test", "type1", "1").setSource("field", 1).execute().actionGet();
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setFields("field")
.setFetchSource(true)
.execute().actionGet();
@ -540,7 +368,7 @@ public class UpdateIT extends ESIntegTestCase {
// check _source parameter
client().prepareIndex("test", "type1", "1").setSource("field1", 1, "field2", 2).execute().actionGet();
updateResponse = client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field1", Collections.emptyMap()))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field1")))
.setFetchSource("field1", "field2")
.get();
assertThat(updateResponse.getIndex(), equalTo("test"));
@ -600,10 +428,11 @@ public class UpdateIT extends ESIntegTestCase {
createTestIndex();
ensureGreen();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
try {
client().prepareUpdate(indexOrAlias(), "type1", "1")
.setDoc(XContentFactory.jsonBuilder().startObject().field("field", 1).endObject())
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.execute().actionGet();
fail("Should have thrown ActionRequestValidationException");
} catch (ActionRequestValidationException e) {
@ -616,9 +445,10 @@ public class UpdateIT extends ESIntegTestCase {
public void testUpdateRequestWithScriptAndShouldUpsertDoc() throws Exception {
createTestIndex();
ensureGreen();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
try {
client().prepareUpdate(indexOrAlias(), "type1", "1")
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setDocAsUpsert(true)
.execute().actionGet();
fail("Should have thrown ActionRequestValidationException");
@ -667,7 +497,7 @@ public class UpdateIT extends ESIntegTestCase {
// Update the first object and note context variables values
UpdateResponse updateResponse = client().prepareUpdate("test", "subtype1", "id1")
.setRouting("routing1")
.setScript(new Script(ScriptType.INLINE, "extract_ctx", "", Collections.emptyMap()))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, EXTRACT_CTX_SCRIPT, Collections.emptyMap()))
.execute().actionGet();
assertEquals(2, updateResponse.getVersion());
@ -683,7 +513,7 @@ public class UpdateIT extends ESIntegTestCase {
// Idem with the second object
updateResponse = client().prepareUpdate("test", "type1", "parentId1")
.setScript(new Script(ScriptType.INLINE, "extract_ctx", "", Collections.emptyMap()))
.setScript(new Script(ScriptType.INLINE, UPDATE_SCRIPTS, EXTRACT_CTX_SCRIPT, Collections.emptyMap()))
.execute().actionGet();
assertEquals(2, updateResponse.getVersion());
@ -710,6 +540,7 @@ public class UpdateIT extends ESIntegTestCase {
final int numberOfUpdatesPerThread = scaledRandomIntBetween(100, 500);
final List<Exception> failures = new CopyOnWriteArrayList<>();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
for (int i = 0; i < numberOfThreads; i++) {
Runnable r = new Runnable() {
@Override
@ -722,13 +553,13 @@ public class UpdateIT extends ESIntegTestCase {
}
if (useBulkApi) {
UpdateRequestBuilder updateRequestBuilder = client().prepareUpdate(indexOrAlias(), "type1", Integer.toString(i))
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setRetryOnConflict(Integer.MAX_VALUE)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject());
client().prepareBulk().add(updateRequestBuilder).execute().actionGet();
} else {
client().prepareUpdate(indexOrAlias(), "type1", Integer.toString(i))
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setRetryOnConflict(Integer.MAX_VALUE)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject())
.execute().actionGet();
@ -773,6 +604,7 @@ public class UpdateIT extends ESIntegTestCase {
.setSettings(Settings.builder().put(MergePolicyConfig.INDEX_MERGE_ENABLED, false)));
ensureGreen();
Script fieldIncScript = new Script(ScriptType.INLINE, UPDATE_SCRIPTS, FIELD_INC_SCRIPT, Collections.singletonMap("field", "field"));
final int numberOfThreads = scaledRandomIntBetween(3,5);
final int numberOfIdsPerThread = scaledRandomIntBetween(3,10);
final int numberOfUpdatesPerId = scaledRandomIntBetween(10,100);
@ -848,7 +680,7 @@ public class UpdateIT extends ESIntegTestCase {
updateRequestsOutstanding.acquire();
try {
UpdateRequest ur = client().prepareUpdate("test", "type1", Integer.toString(j))
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setRetryOnConflict(retryOnConflict)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject())
.request();
@ -948,7 +780,7 @@ public class UpdateIT extends ESIntegTestCase {
//All the previous operations should be complete or failed at this point
for (int i = 0; i < numberOfIdsPerThread; ++i) {
UpdateResponse ur = client().prepareUpdate("test", "type1", Integer.toString(i))
.setScript(new Script(ScriptType.INLINE, "field_inc", "field", Collections.emptyMap()))
.setScript(fieldIncScript)
.setRetryOnConflict(Integer.MAX_VALUE)
.setUpsert(jsonBuilder().startObject().field("field", 1).endObject())
.execute().actionGet();

View File

@ -98,13 +98,13 @@ public class MockScriptEngine implements ScriptEngine {
private final String name;
private final String source;
private final Map<String, String> params;
private final Map<String, String> options;
private final Function<Map<String, Object>, Object> script;
public MockCompiledScript(String name, Map<String, String> params, String source, Function<Map<String, Object>, Object> script) {
public MockCompiledScript(String name, Map<String, String> options, String source, Function<Map<String, Object>, Object> script) {
this.name = name;
this.source = source;
this.params = params;
this.options = options;
this.script = script;
}
@ -112,24 +112,28 @@ public class MockScriptEngine implements ScriptEngine {
return name;
}
public ExecutableScript createExecutableScript(Map<String, Object> vars) {
public ExecutableScript createExecutableScript(Map<String, Object> params) {
Map<String, Object> context = new HashMap<>();
if (params != null) {
context.putAll(params);
if (options != null) {
context.putAll(options); // TODO: remove this once scripts know to look for options under options key
context.put("options", options);
}
if (vars != null) {
context.putAll(vars);
if (params != null) {
context.putAll(params); // TODO: remove this once scripts know to look for params under params key
context.put("params", params);
}
return new MockExecutableScript(context, script != null ? script : ctx -> source);
}
public SearchScript createSearchScript(Map<String, Object> vars, SearchLookup lookup) {
public SearchScript createSearchScript(Map<String, Object> params, SearchLookup lookup) {
Map<String, Object> context = new HashMap<>();
if (params != null) {
context.putAll(params);
if (options != null) {
context.putAll(options); // TODO: remove this once scripts know to look for options under options key
context.put("options", options);
}
if (vars != null) {
context.putAll(vars);
if (params != null) {
context.putAll(params); // TODO: remove this once scripts know to look for params under params key
context.put("params", params);
}
return new MockSearchScript(lookup, context, script != null ? script : ctx -> source);
}