Browse Source

Move mov_fn agg to module (#90836)

This continues to populate the `aggregations` module with it's first
pipeline aggregation and it's first custom script context.

Relates to #90283
Nik Everett 3 years ago
parent
commit
9660e8b1c2
31 changed files with 250 additions and 133 deletions
  1. 10 1
      modules/aggregations/build.gradle
  2. 5 0
      modules/aggregations/src/main/java/module-info.java
  3. 38 0
      modules/aggregations/src/main/java/org/elasticsearch/aggregations/AggregationsPainlessExtension.java
  4. 21 2
      modules/aggregations/src/main/java/org/elasticsearch/aggregations/AggregationsPlugin.java
  5. 3 1
      modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregationBuilder.java
  6. 4 1
      modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregator.java
  7. 1 1
      modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovingFunctionScript.java
  8. 9 0
      modules/aggregations/src/main/resources/META-INF/services/org.elasticsearch.painless.spi.PainlessExtension
  9. 1 1
      modules/aggregations/src/main/resources/org/elasticsearch/aggregations/moving_function_whitelist.txt
  10. 43 11
      modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/MovFnAggregatorTests.java
  11. 8 1
      modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregationBuilderSerializationTests.java
  12. 1 1
      modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/PipelineAggregationHelperTests.java
  13. 0 0
      modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/adjacency_matrix.yml
  14. 47 0
      modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/moving_fn.yml
  15. 8 0
      modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/painless_execute.yml
  16. 2 1
      modules/lang-painless/build.gradle
  17. 39 0
      modules/lang-painless/spi/src/main/java/org/elasticsearch/painless/spi/PainlessTestScript.java
  18. 3 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java
  19. 1 26
      modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java
  20. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/AliasTests.java
  21. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java
  22. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/DynamicTypeTests.java
  23. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java
  24. 0 5
      modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java
  25. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/action/SuggestTests.java
  26. 0 47
      rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/250_moving_fn.yml
  27. 0 2
      server/src/main/java/org/elasticsearch/script/ScriptModule.java
  28. 0 8
      server/src/main/java/org/elasticsearch/search/SearchModule.java
  29. 0 5
      server/src/main/java/org/elasticsearch/search/aggregations/PipelineAggregatorBuilders.java
  30. 1 1
      server/src/test/java/org/elasticsearch/script/ScriptLanguagesInfoTests.java
  31. 0 11
      test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java

+ 10 - 1
modules/aggregations/build.gradle

@@ -12,11 +12,12 @@ apply plugin: 'elasticsearch.internal-cluster-test'
 esplugin {
   description 'Adds "built in" aggregations to Elasticsearch.'
   classname 'org.elasticsearch.aggregations.AggregationsPlugin'
+  extendedPlugins = ['lang-painless']
 }
 
 restResources {
   restApi {
-    include '_common', 'indices', 'cluster', 'index', 'search', 'nodes', 'bulk'
+    include '_common', 'indices', 'cluster', 'index', 'search', 'nodes', 'bulk', 'scripts_painless_execute'
   }
   restTests {
     // Pulls in all aggregation tests from core AND the forwards v7's core for forwards compatibility
@@ -38,3 +39,11 @@ tasks.named("yamlRestTestV7CompatTransform").configure { task ->
 artifacts {
   restTests(new File(projectDir, "src/yamlRestTest/resources/rest-api-spec/test"))
 }
+
+testClusters.configureEach {
+  module ':modules:lang-painless'
+}
+
+dependencies {
+  compileOnly(project(':modules:lang-painless:spi'))
+}

+ 5 - 0
modules/aggregations/src/main/java/module-info.java

@@ -8,11 +8,16 @@
 
 module org.elasticsearch.aggs {
     requires org.elasticsearch.base;
+    requires org.elasticsearch.painless.spi;
     requires org.elasticsearch.server;
     requires org.elasticsearch.xcontent;
     requires org.apache.lucene.core;
 
     exports org.elasticsearch.aggregations.bucket.histogram;
     exports org.elasticsearch.aggregations.bucket.adjacency;
+    exports org.elasticsearch.aggregations.pipeline;
 
+    opens org.elasticsearch.aggregations to org.elasticsearch.painless.spi; // whitelist resource access
+
+    provides org.elasticsearch.painless.spi.PainlessExtension with org.elasticsearch.aggregations.AggregationsPainlessExtension;
 }

+ 38 - 0
modules/aggregations/src/main/java/org/elasticsearch/aggregations/AggregationsPainlessExtension.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.aggregations;
+
+import org.elasticsearch.aggregations.pipeline.MovingFunctionScript;
+import org.elasticsearch.painless.spi.PainlessExtension;
+import org.elasticsearch.painless.spi.PainlessTestScript;
+import org.elasticsearch.painless.spi.Whitelist;
+import org.elasticsearch.painless.spi.WhitelistLoader;
+import org.elasticsearch.script.ScriptContext;
+import org.elasticsearch.search.aggregations.pipeline.MovingFunctions;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Extends the painless whitelist for the {@link MovingFunctionScript} to include {@link MovingFunctions}.
+ */
+public class AggregationsPainlessExtension implements PainlessExtension {
+    private static final Whitelist MOVING_FUNCTION_ALLOWLIST = WhitelistLoader.loadFromResourceFiles(
+        AggregationsPainlessExtension.class,
+        "moving_function_whitelist.txt"
+    );
+
+    @Override
+    public Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists() {
+        return Map.ofEntries(
+            Map.entry(MovingFunctionScript.CONTEXT, List.of(MOVING_FUNCTION_ALLOWLIST)),
+            Map.entry(PainlessTestScript.CONTEXT, List.of(MOVING_FUNCTION_ALLOWLIST))
+        );
+    }
+}

+ 21 - 2
modules/aggregations/src/main/java/org/elasticsearch/aggregations/AggregationsPlugin.java

@@ -12,13 +12,16 @@ import org.elasticsearch.aggregations.bucket.adjacency.AdjacencyMatrixAggregatio
 import org.elasticsearch.aggregations.bucket.adjacency.InternalAdjacencyMatrix;
 import org.elasticsearch.aggregations.bucket.histogram.AutoDateHistogramAggregationBuilder;
 import org.elasticsearch.aggregations.bucket.histogram.InternalAutoDateHistogram;
+import org.elasticsearch.aggregations.pipeline.MovFnPipelineAggregationBuilder;
+import org.elasticsearch.aggregations.pipeline.MovingFunctionScript;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.plugins.SearchPlugin;
+import org.elasticsearch.script.ScriptContext;
 
 import java.util.List;
 
-public class AggregationsPlugin extends Plugin implements SearchPlugin {
-
+public class AggregationsPlugin extends Plugin implements SearchPlugin, ScriptPlugin {
     @Override
     public List<AggregationSpec> getAggregations() {
         return List.of(
@@ -35,4 +38,20 @@ public class AggregationsPlugin extends Plugin implements SearchPlugin {
                 .setAggregatorRegistrar(AutoDateHistogramAggregationBuilder::registerAggregators)
         );
     }
+
+    @Override
+    public List<PipelineAggregationSpec> getPipelineAggregations() {
+        return List.of(
+            new PipelineAggregationSpec(
+                MovFnPipelineAggregationBuilder.NAME,
+                MovFnPipelineAggregationBuilder::new,
+                MovFnPipelineAggregationBuilder.PARSER
+            )
+        );
+    }
+
+    @Override
+    public List<ScriptContext<?>> getContexts() {
+        return List.of(MovingFunctionScript.CONTEXT);
+    }
 }

+ 3 - 1
server/src/main/java/org/elasticsearch/search/aggregations/pipeline/MovFnPipelineAggregationBuilder.java → modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregationBuilder.java

@@ -6,7 +6,7 @@
  * Side Public License, v 1.
  */
 
-package org.elasticsearch.search.aggregations.pipeline;
+package org.elasticsearch.aggregations.pipeline;
 
 import org.elasticsearch.Version;
 import org.elasticsearch.common.Strings;
@@ -14,7 +14,9 @@ import org.elasticsearch.common.io.stream.StreamInput;
 import org.elasticsearch.common.io.stream.StreamOutput;
 import org.elasticsearch.script.Script;
 import org.elasticsearch.search.DocValueFormat;
+import org.elasticsearch.search.aggregations.pipeline.AbstractPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.BucketHelpers.GapPolicy;
+import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
 import org.elasticsearch.xcontent.ConstructingObjectParser;
 import org.elasticsearch.xcontent.ObjectParser;
 import org.elasticsearch.xcontent.ParseField;

+ 4 - 1
server/src/main/java/org/elasticsearch/search/aggregations/pipeline/MovFnPipelineAggregator.java → modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregator.java

@@ -6,7 +6,7 @@
  * Side Public License, v 1.
  */
 
-package org.elasticsearch.search.aggregations.pipeline;
+package org.elasticsearch.aggregations.pipeline;
 
 import org.elasticsearch.script.Script;
 import org.elasticsearch.search.DocValueFormat;
@@ -16,6 +16,9 @@ import org.elasticsearch.search.aggregations.InternalAggregations;
 import org.elasticsearch.search.aggregations.InternalMultiBucketAggregation;
 import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
 import org.elasticsearch.search.aggregations.bucket.histogram.HistogramFactory;
+import org.elasticsearch.search.aggregations.pipeline.BucketHelpers;
+import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
+import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
 
 import java.util.ArrayList;
 import java.util.HashMap;

+ 1 - 1
server/src/main/java/org/elasticsearch/search/aggregations/pipeline/MovingFunctionScript.java → modules/aggregations/src/main/java/org/elasticsearch/aggregations/pipeline/MovingFunctionScript.java

@@ -6,7 +6,7 @@
  * Side Public License, v 1.
  */
 
-package org.elasticsearch.search.aggregations.pipeline;
+package org.elasticsearch.aggregations.pipeline;
 
 import org.elasticsearch.script.ScriptContext;
 import org.elasticsearch.script.ScriptFactory;

+ 9 - 0
modules/aggregations/src/main/resources/META-INF/services/org.elasticsearch.painless.spi.PainlessExtension

@@ -0,0 +1,9 @@
+#
+# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+# or more contributor license agreements. Licensed under the Elastic License
+# 2.0 and the Server Side Public License, v 1; you may not use this file except
+# in compliance with, at your election, the Elastic License 2.0 or the Server
+# Side Public License, v 1.
+#
+
+org.elasticsearch.aggregations.AggregationsPainlessExtension

+ 1 - 1
modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.script.moving_function.txt → modules/aggregations/src/main/resources/org/elasticsearch/aggregations/moving_function_whitelist.txt

@@ -6,7 +6,7 @@
 # Side Public License, v 1.
 #
 
-# This file contains a whitelist for the Moving Function pipeline aggregator in core
+# This file contains a allowlist for the Moving Function pipeline aggregator
 
 class org.elasticsearch.search.aggregations.pipeline.MovingFunctions {
   double max(double[])

+ 43 - 11
server/src/test/java/org/elasticsearch/search/aggregations/pipeline/MovFnAggrgatorTests.java → modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/MovFnAggregatorTests.java

@@ -6,7 +6,7 @@
  * Side Public License, v 1.
  */
 
-package org.elasticsearch.search.aggregations.pipeline;
+package org.elasticsearch.aggregations.pipeline;
 
 import org.apache.lucene.document.Document;
 import org.apache.lucene.document.LongPoint;
@@ -24,10 +24,9 @@ import org.elasticsearch.common.time.DateFormatters;
 import org.elasticsearch.index.mapper.DateFieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.NumberFieldMapper;
-import org.elasticsearch.script.MockScriptEngine;
 import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptContext;
 import org.elasticsearch.script.ScriptEngine;
-import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService;
 import org.elasticsearch.script.ScriptType;
 import org.elasticsearch.search.aggregations.AggregatorTestCase;
@@ -36,17 +35,20 @@ import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInter
 import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
 import org.elasticsearch.search.aggregations.bucket.histogram.InternalDateHistogram;
 import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
+import org.elasticsearch.search.aggregations.pipeline.InternalSimpleValue;
+import org.elasticsearch.search.aggregations.pipeline.MovingFunctions;
 
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Consumer;
 
 import static org.hamcrest.Matchers.equalTo;
 
-public class MovFnAggrgatorTests extends AggregatorTestCase {
+public class MovFnAggregatorTests extends AggregatorTestCase {
 
     private static final String DATE_FIELD = "date";
     private static final String INSTANT_FIELD = "instant";
@@ -69,14 +71,44 @@ public class MovFnAggrgatorTests extends AggregatorTestCase {
 
     @Override
     protected ScriptService getMockScriptService() {
-        MockScriptEngine scriptEngine = new MockScriptEngine(
-            MockScriptEngine.NAME,
-            Collections.singletonMap("test", script -> MovingFunctions.max((double[]) script.get("_values"))),
-            Collections.emptyMap()
-        );
+        ScriptEngine scriptEngine = new ScriptEngine() {
+            @Override
+            public String getType() {
+                return "test";
+            }
+
+            @Override
+            public <FactoryType> FactoryType compile(
+                String name,
+                String code,
+                ScriptContext<FactoryType> context,
+                Map<String, String> params
+            ) {
+                if (getSupportedContexts().contains(context) == false) {
+                    return null;
+                }
+                MovingFunctionScript.Factory factory = () -> new MovingFunctionScript() {
+                    @Override
+                    public double execute(Map<String, Object> params, double[] values) {
+                        return MovingFunctions.max(values);
+                    }
+                };
+                return context.factoryClazz.cast(factory);
+            }
+
+            @Override
+            public Set<ScriptContext<?>> getSupportedContexts() {
+                return Set.of(MovingFunctionScript.CONTEXT);
+            }
+        };
         Map<String, ScriptEngine> engines = Collections.singletonMap(scriptEngine.getType(), scriptEngine);
 
-        return new ScriptService(Settings.EMPTY, engines, ScriptModule.CORE_CONTEXTS, () -> 1L);
+        return new ScriptService(
+            Settings.EMPTY,
+            engines,
+            Map.of(MovingFunctionScript.CONTEXT.name, MovingFunctionScript.CONTEXT),
+            () -> 1L
+        );
     }
 
     public void testMatchAllDocs() throws IOException {
@@ -94,7 +126,7 @@ public class MovFnAggrgatorTests extends AggregatorTestCase {
     }
 
     private void check(int shift, int window, List<Double> expected) throws IOException {
-        Script script = new Script(ScriptType.INLINE, MockScriptEngine.NAME, "test", Collections.emptyMap());
+        Script script = new Script(ScriptType.INLINE, "test", "test", Collections.emptyMap());
         MovFnPipelineAggregationBuilder builder = new MovFnPipelineAggregationBuilder("mov_fn", "avg", script, window);
         builder.setShift(shift);
 

+ 8 - 1
modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/MovFnPipelineAggregationBuilderSerializationTests.java

@@ -8,14 +8,16 @@
 
 package org.elasticsearch.aggregations.pipeline;
 
+import org.elasticsearch.aggregations.AggregationsPlugin;
+import org.elasticsearch.plugins.SearchPlugin;
 import org.elasticsearch.script.Script;
 import org.elasticsearch.search.aggregations.AggregationBuilder;
 import org.elasticsearch.search.aggregations.BasePipelineAggregationTestCase;
 import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
-import org.elasticsearch.search.aggregations.pipeline.MovFnPipelineAggregationBuilder;
 
 import java.io.IOException;
 import java.util.Collections;
+import java.util.List;
 
 import static java.util.Collections.emptyList;
 import static java.util.Collections.emptyMap;
@@ -23,6 +25,11 @@ import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.nullValue;
 
 public class MovFnPipelineAggregationBuilderSerializationTests extends BasePipelineAggregationTestCase<MovFnPipelineAggregationBuilder> {
+    @Override
+    protected List<SearchPlugin> plugins() {
+        return List.of(new AggregationsPlugin());
+    }
+
     @Override
     protected MovFnPipelineAggregationBuilder createTestAggregatorFactory() {
         MovFnPipelineAggregationBuilder builder = new MovFnPipelineAggregationBuilder(

+ 1 - 1
modules/aggregations/src/test/java/org/elasticsearch/aggregations/pipeline/PipelineAggregationHelperTests.java

@@ -134,7 +134,7 @@ public class PipelineAggregationHelperTests extends ESTestCase {
         return 0.0;
     }
 
-    static AggregationBuilder getRandomSequentiallyOrderedParentAgg() throws IOException {
+    public static AggregationBuilder getRandomSequentiallyOrderedParentAgg() throws IOException {
         @SuppressWarnings("unchecked")
         Function<String, AggregationBuilder> builder = randomFrom(
             HistogramAggregationBuilder::new,

+ 0 - 0
modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/70_adjacency_matrix.yml → modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/adjacency_matrix.yml


+ 47 - 0
modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/70_moving_fn_agg.yml → modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/moving_fn.yml

@@ -765,3 +765,50 @@ bad path:
                     buckets_path: "missing"
                     window: 2
                     script: "MovingFunctions.min(values)"
+
+---
+"Bad window":
+
+  - skip:
+      version: " - 7.1.99"
+      reason:  "calendar_interval added in 7.2"
+
+  - do:
+      catch: /\[window\] must be a positive, non-zero integer\./
+      search:
+        rest_total_hits_as_int: true
+        body:
+          size: 0
+          aggs:
+            the_histo:
+              date_histogram:
+                field: "date"
+                calendar_interval: "1d"
+              aggs:
+                the_avg:
+                  avg:
+                    field: "value_field"
+                the_mov_fn:
+                  moving_fn:
+                    buckets_path: "the_avg"
+                    window: -1
+                    script: "MovingFunctions.max(values)"
+
+---
+"Not under date_histo":
+
+  - do:
+      catch: /moving_fn aggregation \[the_mov_fn\] must have a histogram, date_histogram or auto_date_histogram as parent but doesn't have a parent/
+      search:
+        rest_total_hits_as_int: true
+        body:
+          size: 0
+          aggs:
+            the_avg:
+              avg:
+                field: "value_field"
+            the_mov_fn:
+              moving_fn:
+                buckets_path: "the_avg"
+                window: 1
+                script: "MovingFunctions.max(values)"

+ 8 - 0
modules/aggregations/src/yamlRestTest/resources/rest-api-spec/test/aggregations/painless_execute.yml

@@ -0,0 +1,8 @@
+---
+MovingFunctions are available in the default context:
+  - do:
+      scripts_painless_execute:
+        body:
+          script:
+            source: "MovingFunctions.max(new double[] {1.0, 2.0, -1234})"
+  - match: { result: "2.0" }

+ 2 - 1
modules/lang-painless/build.gradle

@@ -96,7 +96,8 @@ tasks.named("yamlRestTestV7CompatTest").configure {
             'painless/40_fields_api/script fields api for dates',
             'painless/70_execute_painless_scripts/Execute with double field context (multi-value, fields api)',
             'painless/40_fields_api/filter script fields api',
-            'painless/40_fields_api/script score fields api'
+            'painless/40_fields_api/script score fields api',
+            'painless/70_mov_fn_agg/*' // Agg moved to a module.
     ].join(',')
 }
 

+ 39 - 0
modules/lang-painless/spi/src/main/java/org/elasticsearch/painless/spi/PainlessTestScript.java

@@ -0,0 +1,39 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+package org.elasticsearch.painless.spi;
+
+import org.elasticsearch.script.ScriptContext;
+
+import java.util.Map;
+
+/**
+ * Generic "test" context used by the painless execute REST API
+ * for testing painless scripts.
+ */
+public abstract class PainlessTestScript {
+    private final Map<String, Object> params;
+
+    public PainlessTestScript(Map<String, Object> params) {
+        this.params = params;
+    }
+
+    /** Return the parameters for this script. */
+    public Map<String, Object> getParams() {
+        return params;
+    }
+
+    public abstract Object execute();
+
+    public interface Factory {
+        PainlessTestScript newInstance(Map<String, Object> params);
+    }
+
+    public static final String[] PARAMETERS = {};
+    public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("painless_test", Factory.class);
+}

+ 3 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java

@@ -27,6 +27,7 @@ import org.elasticsearch.env.NodeEnvironment;
 import org.elasticsearch.painless.action.PainlessContextAction;
 import org.elasticsearch.painless.action.PainlessExecuteAction;
 import org.elasticsearch.painless.spi.PainlessExtension;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.spi.WhitelistLoader;
 import org.elasticsearch.painless.spi.annotation.WhitelistAnnotationParser;
@@ -111,7 +112,7 @@ public final class PainlessPlugin extends Plugin implements ScriptPlugin, Extens
             }
         }
         testWhitelists.add(WhitelistLoader.loadFromResourceFiles(PainlessPlugin.class, "org.elasticsearch.json.txt"));
-        whitelists.put(PainlessExecuteAction.PainlessTestScript.CONTEXT, testWhitelists);
+        whitelists.put(PainlessTestScript.CONTEXT, testWhitelists);
     }
 
     private final SetOnce<PainlessScriptEngine> painlessScriptEngine = new SetOnce<>();
@@ -171,7 +172,7 @@ public final class PainlessPlugin extends Plugin implements ScriptPlugin, Extens
 
     @Override
     public List<ScriptContext<?>> getContexts() {
-        return Collections.singletonList(PainlessExecuteAction.PainlessTestScript.CONTEXT);
+        return Collections.singletonList(PainlessTestScript.CONTEXT);
     }
 
     @Override

+ 1 - 26
modules/lang-painless/src/main/java/org/elasticsearch/painless/action/PainlessExecuteAction.java

@@ -56,6 +56,7 @@ import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.index.shard.ShardId;
 import org.elasticsearch.indices.IndicesService;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.rest.BaseRestHandler;
 import org.elasticsearch.rest.RestRequest;
 import org.elasticsearch.rest.action.RestToXContentListener;
@@ -433,32 +434,6 @@ public class PainlessExecuteAction extends ActionType<PainlessExecuteAction.Resp
         }
     }
 
-    public abstract static class PainlessTestScript {
-
-        private final Map<String, Object> params;
-
-        public PainlessTestScript(Map<String, Object> params) {
-            this.params = params;
-        }
-
-        /** Return the parameters for this script. */
-        public Map<String, Object> getParams() {
-            return params;
-        }
-
-        public abstract Object execute();
-
-        public interface Factory {
-
-            PainlessTestScript newInstance(Map<String, Object> params);
-
-        }
-
-        public static final String[] PARAMETERS = {};
-        public static final ScriptContext<Factory> CONTEXT = new ScriptContext<>("painless_test", Factory.class);
-
-    }
-
     public static class TransportAction extends TransportSingleShardAction<Request, Response> {
 
         private final ScriptService scriptService;

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/AliasTests.java

@@ -8,8 +8,8 @@
 
 package org.elasticsearch.painless;
 
-import org.elasticsearch.painless.action.PainlessExecuteAction.PainlessTestScript;
 import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.spi.WhitelistLoader;
 import org.elasticsearch.script.ScriptContext;

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java

@@ -8,10 +8,10 @@
 
 package org.elasticsearch.painless;
 
-import org.elasticsearch.painless.action.PainlessExecuteAction.PainlessTestScript;
 import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
 import org.elasticsearch.painless.phase.IRTreeVisitor;
 import org.elasticsearch.painless.phase.UserTreeVisitor;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.symbol.ScriptScope;
 import org.elasticsearch.painless.symbol.WriteScope;

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/DynamicTypeTests.java

@@ -8,7 +8,7 @@
 
 package org.elasticsearch.painless;
 
-import org.elasticsearch.painless.action.PainlessExecuteAction.PainlessTestScript;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.spi.WhitelistLoader;
 import org.elasticsearch.script.ScriptContext;

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java

@@ -12,6 +12,7 @@ import junit.framework.AssertionFailedError;
 
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.painless.antlr.Walker;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.spi.WhitelistLoader;
 import org.elasticsearch.script.ScriptContext;
@@ -25,7 +26,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.elasticsearch.painless.action.PainlessExecuteAction.PainlessTestScript;
 import static org.hamcrest.Matchers.hasSize;
 
 /**

+ 0 - 5
modules/lang-painless/src/test/java/org/elasticsearch/painless/action/PainlessExecuteApiTests.java

@@ -390,11 +390,6 @@ public class PainlessExecuteApiTests extends ESSingleNodeTestCase {
         response = innerShardOperation(request, scriptService, null);
         assertEquals("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", response.getResult());
 
-        // movfn
-        request = new Request(new Script("MovingFunctions.max(new double[]{1, 3, 2})"), null, null);
-        response = innerShardOperation(request, scriptService, null);
-        assertEquals(3.0, Double.parseDouble((String) response.getResult()), .1);
-
         // json
         request = new Request(new Script("Json.load('{\"a\": 1, \"b\": 2}')['b']"), null, null);
         response = innerShardOperation(request, scriptService, null);

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/action/SuggestTests.java

@@ -11,9 +11,9 @@ package org.elasticsearch.painless.action;
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.Token;
 import org.elasticsearch.painless.ScriptTestCase;
-import org.elasticsearch.painless.action.PainlessExecuteAction.PainlessTestScript;
 import org.elasticsearch.painless.antlr.EnhancedSuggestLexer;
 import org.elasticsearch.painless.antlr.SuggestLexer;
+import org.elasticsearch.painless.spi.PainlessTestScript;
 
 import java.util.List;
 

+ 0 - 47
rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/search.aggregation/250_moving_fn.yml

@@ -1,47 +0,0 @@
-# There are many more tests under modules/lang-painless/...moving_fn.yml so they can use painless
----
-"Bad window":
-
-  - skip:
-      version: " - 7.1.99"
-      reason:  "calendar_interval added in 7.2"
-
-  - do:
-      catch: /\[window\] must be a positive, non-zero integer\./
-      search:
-        rest_total_hits_as_int: true
-        body:
-          size: 0
-          aggs:
-            the_histo:
-              date_histogram:
-                field: "date"
-                calendar_interval: "1d"
-              aggs:
-                the_avg:
-                  avg:
-                    field: "value_field"
-                the_mov_fn:
-                  moving_fn:
-                    buckets_path: "the_avg"
-                    window: -1
-                    script: "MovingFunctions.max(values)"
-
----
-"Not under date_histo":
-
-  - do:
-      catch: /moving_fn aggregation \[the_mov_fn\] must have a histogram, date_histogram or auto_date_histogram as parent but doesn't have a parent/
-      search:
-        rest_total_hits_as_int: true
-        body:
-          size: 0
-          aggs:
-            the_avg:
-              avg:
-                field: "value_field"
-            the_mov_fn:
-              moving_fn:
-                buckets_path: "the_avg"
-                window: 1
-                script: "MovingFunctions.max(values)"

+ 0 - 2
server/src/main/java/org/elasticsearch/script/ScriptModule.java

@@ -12,7 +12,6 @@ import org.elasticsearch.common.settings.ClusterSettings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.query.IntervalFilterScript;
 import org.elasticsearch.plugins.ScriptPlugin;
-import org.elasticsearch.search.aggregations.pipeline.MovingFunctionScript;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -63,7 +62,6 @@ public class ScriptModule {
                 SimilarityWeightScript.CONTEXT,
                 TemplateScript.CONTEXT,
                 TemplateScript.INGEST_CONTEXT,
-                MovingFunctionScript.CONTEXT,
                 ScriptedMetricAggContexts.InitScript.CONTEXT,
                 ScriptedMetricAggContexts.MapScript.CONTEXT,
                 ScriptedMetricAggContexts.CombineScript.CONTEXT,

+ 0 - 8
server/src/main/java/org/elasticsearch/search/SearchModule.java

@@ -204,7 +204,6 @@ import org.elasticsearch.search.aggregations.pipeline.InternalStatsBucket;
 import org.elasticsearch.search.aggregations.pipeline.MaxBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.MinBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.MovAvgPipelineAggregationBuilder;
-import org.elasticsearch.search.aggregations.pipeline.MovFnPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.PercentilesBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.SerialDiffPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.StatsBucketPipelineAggregationBuilder;
@@ -791,13 +790,6 @@ public class SearchModule {
                 SerialDiffPipelineAggregationBuilder::parse
             )
         );
-        registerPipelineAggregation(
-            new PipelineAggregationSpec(
-                MovFnPipelineAggregationBuilder.NAME,
-                MovFnPipelineAggregationBuilder::new,
-                MovFnPipelineAggregationBuilder.PARSER
-            )
-        );
         if (RestApiVersion.minimumSupported() == RestApiVersion.V_7) {
             registerPipelineAggregation(
                 new PipelineAggregationSpec(

+ 0 - 5
server/src/main/java/org/elasticsearch/search/aggregations/PipelineAggregatorBuilders.java

@@ -18,7 +18,6 @@ import org.elasticsearch.search.aggregations.pipeline.DerivativePipelineAggregat
 import org.elasticsearch.search.aggregations.pipeline.ExtendedStatsBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.MaxBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.MinBucketPipelineAggregationBuilder;
-import org.elasticsearch.search.aggregations.pipeline.MovFnPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.PercentilesBucketPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.SerialDiffPipelineAggregationBuilder;
 import org.elasticsearch.search.aggregations.pipeline.StatsBucketPipelineAggregationBuilder;
@@ -91,8 +90,4 @@ public final class PipelineAggregatorBuilders {
     public static SerialDiffPipelineAggregationBuilder diff(String name, String bucketsPath) {
         return new SerialDiffPipelineAggregationBuilder(name, bucketsPath);
     }
-
-    public static MovFnPipelineAggregationBuilder movingFunction(String name, Script script, String bucketsPaths, int window) {
-        return new MovFnPipelineAggregationBuilder(name, bucketsPaths, script, window);
-    }
 }

+ 1 - 1
server/src/test/java/org/elasticsearch/script/ScriptLanguagesInfoTests.java

@@ -106,7 +106,7 @@ public class ScriptLanguagesInfoTests extends ESTestCase {
             .collect(Collectors.toMap(c -> c.name, Function.identity()));
 
         List<String> allContexts = new ArrayList<>(mockContexts.keySet());
-        List<String> allowed = allContexts.subList(0, allContexts.size() / 2);
+        List<String> allowed = new ArrayList<>(allContexts.subList(0, allContexts.size() / 2));
         String miscContext = "misc_context";
         allowed.add(miscContext);
         // check that allowing more than available doesn't pollute the returned contexts

+ 0 - 11
test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java

@@ -20,7 +20,6 @@ import org.elasticsearch.index.similarity.ScriptedSimilarity.Doc;
 import org.elasticsearch.index.similarity.ScriptedSimilarity.Field;
 import org.elasticsearch.index.similarity.ScriptedSimilarity.Query;
 import org.elasticsearch.index.similarity.ScriptedSimilarity.Term;
-import org.elasticsearch.search.aggregations.pipeline.MovingFunctionScript;
 import org.elasticsearch.search.lookup.SearchLookup;
 
 import java.io.IOException;
@@ -251,15 +250,6 @@ public class MockScriptEngine implements ScriptEngine {
         } else if (context.instanceClazz.equals(SimilarityWeightScript.class)) {
             SimilarityWeightScript.Factory factory = mockCompiled::createSimilarityWeightScript;
             return context.factoryClazz.cast(factory);
-        } else if (context.instanceClazz.equals(MovingFunctionScript.class)) {
-            MovingFunctionScript.Factory factory = () -> new MovingFunctionScript() {
-                @Override
-                public double execute(Map<String, Object> params1, double[] values) {
-                    params1.put("_values", values);
-                    return (double) script.apply(params1);
-                }
-            };
-            return context.factoryClazz.cast(factory);
         } else if (context.instanceClazz.equals(ScoreScript.class)) {
             ScoreScript.Factory factory = new MockScoreScript(script);
             return context.factoryClazz.cast(factory);
@@ -372,7 +362,6 @@ public class MockScriptEngine implements ScriptEngine {
             FilterScript.CONTEXT,
             SimilarityScript.CONTEXT,
             SimilarityWeightScript.CONTEXT,
-            MovingFunctionScript.CONTEXT,
             ScoreScript.CONTEXT,
             ScriptedMetricAggContexts.InitScript.CONTEXT,
             ScriptedMetricAggContexts.MapScript.CONTEXT,