Selaa lähdekoodia

boxplot support for transform 52189 (#96515)

Marantidis Kiriakos 2 vuotta sitten
vanhempi
commit
ea42c2e076

+ 5 - 0
docs/changelog/96515.yaml

@@ -0,0 +1,5 @@
+pr: 96515
+summary: Support boxplot aggregation in transform
+area: Transform
+type: enhancement
+issues: []

+ 1 - 0
docs/reference/rest-api/common-parms.asciidoc

@@ -767,6 +767,7 @@ currently supported:
 +
 --
 * <<search-aggregations-metrics-avg-aggregation,Average>>
+* <<search-aggregations-metrics-boxplot-aggregation,Boxplot>>
 * <<search-aggregations-pipeline-bucket-script-aggregation,Bucket script>>
 * <<search-aggregations-pipeline-bucket-selector-aggregation,Bucket selector>>
 * <<search-aggregations-metrics-cardinality-aggregation,Cardinality>>

+ 90 - 0
x-pack/plugin/transform/qa/single-node-tests/src/javaRestTest/java/org/elasticsearch/xpack/transform/integration/TransformPivotRestIT.java

@@ -1846,6 +1846,96 @@ public class TransformPivotRestIT extends TransformRestTestCase {
         assertEquals("business_3", actual);
     }
 
+    public void testPivotWithBoxplot() throws Exception {
+        String transformId = "boxplot_transform";
+        String transformIndex = "boxplot_pivot_reviews";
+        setupDataAccessRole(DATA_ACCESS_ROLE, REVIEWS_INDEX_NAME, transformIndex);
+
+        final Request createTransformRequest = createRequestWithAuth(
+            "PUT",
+            getTransformEndpoint() + transformId,
+            BASIC_AUTH_VALUE_TRANSFORM_ADMIN_WITH_SOME_DATA_ACCESS
+        );
+
+        String config = Strings.format("""
+            {
+              "source": {
+                "index": "%s"
+              },
+              "dest": {
+                "index": "%s"
+              },
+              "pivot": {
+                "group_by": {
+                  "reviewer": {
+                    "terms": {
+                      "field": "user_id"
+                    }
+                  }
+                },
+                "aggregations": {
+                  "stars_boxplot": {
+                    "boxplot": {
+                       "field": "stars"
+                    }
+                  }
+                }
+              }
+            }""", REVIEWS_INDEX_NAME, transformIndex);
+
+        createTransformRequest.setJsonEntity(config);
+        Map<String, Object> createTransformResponse = entityAsMap(client().performRequest(createTransformRequest));
+        assertThat(createTransformResponse.get("acknowledged"), equalTo(Boolean.TRUE));
+
+        startAndWaitForTransform(transformId, transformIndex, BASIC_AUTH_VALUE_TRANSFORM_ADMIN_WITH_SOME_DATA_ACCESS);
+        assertTrue(indexExists(transformIndex));
+
+        Map<String, Object> searchResult = getAsMap(transformIndex + "/_search?q=reviewer:user_4");
+        assertEquals(1, XContentMapValues.extractValue("hits.total.value", searchResult));
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.min", searchResult)).get(0),
+            is(equalTo(1.0))
+        );
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.max", searchResult)).get(0),
+            is(equalTo(5.0))
+        );
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q1", searchResult)).get(0), is(equalTo(3.0)));
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q2", searchResult)).get(0), is(equalTo(5.0)));
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q3", searchResult)).get(0), is(equalTo(5.0)));
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.lower", searchResult)).get(0),
+            is(equalTo(1.0))
+        );
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.upper", searchResult)).get(0),
+            is(equalTo(5.0))
+        );
+
+        searchResult = getAsMap(transformIndex + "/_search?q=reviewer:user_1");
+        assertEquals(1, XContentMapValues.extractValue("hits.total.value", searchResult));
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.min", searchResult)).get(0),
+            is(equalTo(1.0))
+        );
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.max", searchResult)).get(0),
+            is(equalTo(5.0))
+        );
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q1", searchResult)).get(0), is(equalTo(3.0)));
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q2", searchResult)).get(0), is(equalTo(5.0)));
+        assertThat(((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.q3", searchResult)).get(0), is(equalTo(5.0)));
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.lower", searchResult)).get(0),
+            is(equalTo(1.0))
+        );
+        assertThat(
+            ((List<?>) XContentMapValues.extractValue("hits.hits._source.stars_boxplot.upper", searchResult)).get(0),
+            is(equalTo(5.0))
+        );
+
+    }
+
     public void testPivotWithAggregateMetricDouble() throws Exception {
         String transformId = "aggregate_metric_double_transform";
         String transformIndex = "aggregate_metric_double_pivot_reviews";

+ 2 - 2
x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/pivot/TransformAggregations.java

@@ -56,7 +56,6 @@ public final class TransformAggregations {
     private static final List<String> UNSUPPORTED_AGGS = Arrays.asList(
         "adjacency_matrix",
         "auto_date_histogram",
-        "boxplot", // https://github.com/elastic/elasticsearch/issues/52189
         "composite", // DONT because it makes no sense
         "date_histogram",
         "date_range",
@@ -120,7 +119,8 @@ public final class TransformAggregations {
         RARE_TERMS("rare_terms", FLATTENED),
         MISSING("missing", LONG),
         TOP_METRICS("top_metrics", SOURCE),
-        STATS("stats", DOUBLE);
+        STATS("stats", DOUBLE),
+        BOXPLOT("boxplot", DOUBLE);
 
         private final String aggregationType;
         private final String targetMapping;

+ 1 - 1
x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/PivotTests.java

@@ -85,7 +85,7 @@ public class PivotTests extends ESTestCase {
     private Client client;
 
     // exclude aggregations from the analytics module as we don't have parser for it here
-    private final Set<String> externalAggregations = Collections.singleton("top_metrics");
+    private final Set<String> externalAggregations = Set.of("top_metrics", "boxplot");
 
     private final Set<String> supportedAggregations = Stream.of(AggregationType.values())
         .map(AggregationType::getName)

+ 21 - 0
x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/TransformAggregationsTests.java

@@ -24,6 +24,7 @@ import org.elasticsearch.search.aggregations.metrics.PercentilesAggregationBuild
 import org.elasticsearch.search.aggregations.metrics.StatsAggregationBuilder;
 import org.elasticsearch.test.ESTestCase;
 import org.elasticsearch.xpack.analytics.AnalyticsPlugin;
+import org.elasticsearch.xpack.analytics.boxplot.BoxplotAggregationBuilder;
 
 import java.util.Arrays;
 import java.util.List;
@@ -136,6 +137,9 @@ public class TransformAggregationsTests extends ESTestCase {
         assertEquals("double", TransformAggregations.resolveTargetMapping("stats", null));
         assertEquals("double", TransformAggregations.resolveTargetMapping("stats", "int"));
 
+        // boxplot
+        assertEquals("double", TransformAggregations.resolveTargetMapping("boxplot", "double"));
+
         // corner case: source type null
         assertEquals(null, TransformAggregations.resolveTargetMapping("min", null));
     }
@@ -365,6 +369,23 @@ public class TransformAggregationsTests extends ESTestCase {
         assertEquals("percentiles", outputTypes.get("filter_1.filter_2.percentiles.99_5"));
     }
 
+    public void testGetAggregationOutputTypesBoxplot() {
+        AggregationBuilder boxplotAggregationBuilder = new BoxplotAggregationBuilder("boxplot");
+
+        Tuple<Map<String, String>, Map<String, String>> inputAndOutputTypes = TransformAggregations.getAggregationInputAndOutputTypes(
+            boxplotAggregationBuilder
+        );
+        Map<String, String> outputTypes = inputAndOutputTypes.v2();
+        assertEquals(7, outputTypes.size());
+        assertEquals("boxplot", outputTypes.get("boxplot.min"));
+        assertEquals("boxplot", outputTypes.get("boxplot.max"));
+        assertEquals("boxplot", outputTypes.get("boxplot.q1"));
+        assertEquals("boxplot", outputTypes.get("boxplot.q2"));
+        assertEquals("boxplot", outputTypes.get("boxplot.q3"));
+        assertEquals("boxplot", outputTypes.get("boxplot.lower"));
+        assertEquals("boxplot", outputTypes.get("boxplot.upper"));
+    }
+
     public void testGenerateKeyForRange() {
         assertThat(TransformAggregations.generateKeyForRange(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), is(equalTo("*-*")));
         assertThat(TransformAggregations.generateKeyForRange(Double.NEGATIVE_INFINITY, 0.0), is(equalTo("*-0")));