diff --git a/core/src/main/java/org/opensearch/sql/executor/Explain.java b/core/src/main/java/org/opensearch/sql/executor/Explain.java index db2f4bdb11..7c16e0b720 100644 --- a/core/src/main/java/org/opensearch/sql/executor/Explain.java +++ b/core/src/main/java/org/opensearch/sql/executor/Explain.java @@ -23,6 +23,7 @@ import org.opensearch.sql.planner.physical.EvalOperator; import org.opensearch.sql.planner.physical.FilterOperator; import org.opensearch.sql.planner.physical.LimitOperator; +import org.opensearch.sql.planner.physical.NestedOperator; import org.opensearch.sql.planner.physical.PhysicalPlan; import org.opensearch.sql.planner.physical.PhysicalPlanNodeVisitor; import org.opensearch.sql.planner.physical.ProjectOperator; @@ -142,6 +143,12 @@ public ExplainResponseNode visitLimit(LimitOperator node, Object context) { "limit", node.getLimit(), "offset", node.getOffset()))); } + @Override + public ExplainResponseNode visitNested(NestedOperator node, Object context) { + return explain(node, context, explanNode -> explanNode.setDescription(ImmutableMap.of( + "nested", node.getFields()))); + } + protected ExplainResponseNode explain(PhysicalPlan node, Object context, Consumer doExplain) { ExplainResponseNode explainNode = new ExplainResponseNode(getOperatorName(node)); diff --git a/core/src/test/java/org/opensearch/sql/executor/ExplainTest.java b/core/src/test/java/org/opensearch/sql/executor/ExplainTest.java index c2763e7120..7d438c870d 100644 --- a/core/src/test/java/org/opensearch/sql/executor/ExplainTest.java +++ b/core/src/test/java/org/opensearch/sql/executor/ExplainTest.java @@ -22,6 +22,7 @@ import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.eval; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.filter; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.limit; +import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.nested; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.project; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.rareTopN; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.remove; @@ -30,10 +31,9 @@ import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.values; import static org.opensearch.sql.planner.physical.PhysicalPlanDSL.window; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.DisplayNameGeneration; @@ -83,20 +83,20 @@ void can_explain_project_filter_table_scan() { new ExplainResponse( new ExplainResponseNode( "ProjectOperator", - ImmutableMap.of("fields", "[name, age]"), + Map.of("fields", "[name, age]"), singletonList(new ExplainResponseNode( "FilterOperator", - ImmutableMap.of("conditions", "and(=(balance, 10000), >(age, 30))"), + Map.of("conditions", "and(=(balance, 10000), >(age, 30))"), singletonList(tableScan.explainNode()))))), explain.apply(plan)); } @Test void can_explain_aggregations() { - List aggExprs = ImmutableList.of(ref("balance", DOUBLE)); - List aggList = ImmutableList.of( + List aggExprs = List.of(ref("balance", DOUBLE)); + List aggList = List.of( named("avg(balance)", DSL.avg(aggExprs.toArray(new Expression[0])))); - List groupByList = ImmutableList.of( + List groupByList = List.of( named("state", ref("state", STRING))); PhysicalPlan plan = agg(new FakeTableScan(), aggList, groupByList); @@ -104,7 +104,7 @@ void can_explain_aggregations() { new ExplainResponse( new ExplainResponseNode( "AggregationOperator", - ImmutableMap.of( + Map.of( "aggregators", "[avg(balance)]", "groupBy", "[state]"), singletonList(tableScan.explainNode()))), @@ -120,7 +120,7 @@ void can_explain_rare_top_n() { new ExplainResponse( new ExplainResponseNode( "RareTopNOperator", - ImmutableMap.of( + Map.of( "commandType", TOP, "noOfResults", 10, "fields", "[state]", @@ -131,8 +131,8 @@ void can_explain_rare_top_n() { @Test void can_explain_window() { - List partitionByList = ImmutableList.of(DSL.ref("state", STRING)); - List> sortList = ImmutableList.of( + List partitionByList = List.of(DSL.ref("state", STRING)); + List> sortList = List.of( ImmutablePair.of(DEFAULT_ASC, ref("age", INTEGER))); PhysicalPlan plan = window(tableScan, named(DSL.rank()), @@ -142,12 +142,12 @@ void can_explain_window() { new ExplainResponse( new ExplainResponseNode( "WindowOperator", - ImmutableMap.of( + Map.of( "function", "rank()", - "definition", ImmutableMap.of( + "definition", Map.of( "partitionBy", "[state]", - "sortList", ImmutableMap.of( - "age", ImmutableMap.of( + "sortList", Map.of( + "age", Map.of( "sortOrder", "ASC", "nullOrder", "NULL_FIRST")))), singletonList(tableScan.explainNode()))), @@ -157,14 +157,14 @@ void can_explain_window() { @Test void can_explain_other_operators() { ReferenceExpression[] removeList = {ref("state", STRING)}; - Map renameMapping = ImmutableMap.of( + Map renameMapping = Map.of( ref("state", STRING), ref("s", STRING)); Pair evalExprs = ImmutablePair.of( ref("age", INTEGER), DSL.add(ref("age", INTEGER), literal(2))); Expression[] dedupeList = {ref("age", INTEGER)}; Pair sortList = ImmutablePair.of( DEFAULT_ASC, ref("age", INTEGER)); - List values = ImmutableList.of(literal("WA"), literal(30)); + List values = List.of(literal("WA"), literal(30)); PhysicalPlan plan = remove( @@ -183,30 +183,30 @@ void can_explain_other_operators() { new ExplainResponse( new ExplainResponseNode( "RemoveOperator", - ImmutableMap.of("removeList", "[state]"), + Map.of("removeList", "[state]"), singletonList(new ExplainResponseNode( "RenameOperator", - ImmutableMap.of("mapping", ImmutableMap.of("state", "s")), + Map.of("mapping", Map.of("state", "s")), singletonList(new ExplainResponseNode( "EvalOperator", - ImmutableMap.of("expressions", ImmutableMap.of("age", "+(age, 2)")), + Map.of("expressions", Map.of("age", "+(age, 2)")), singletonList(new ExplainResponseNode( "DedupeOperator", - ImmutableMap.of( + Map.of( "dedupeList", "[age]", "allowedDuplication", 1, "keepEmpty", false, "consecutive", false), singletonList(new ExplainResponseNode( "SortOperator", - ImmutableMap.of( - "sortList", ImmutableMap.of( - "age", ImmutableMap.of( + Map.of( + "sortList", Map.of( + "age", Map.of( "sortOrder", "ASC", "nullOrder", "NULL_FIRST"))), singletonList(new ExplainResponseNode( "ValuesOperator", - ImmutableMap.of("values", ImmutableList.of(values)), + Map.of("values", List.of(values)), emptyList()))))))))))) ), explain.apply(plan) @@ -220,7 +220,24 @@ void can_explain_limit() { new ExplainResponse( new ExplainResponseNode( "LimitOperator", - ImmutableMap.of("limit", 10, "offset", 5), + Map.of("limit", 10, "offset", 5), + singletonList(tableScan.explainNode()))), + explain.apply(plan) + ); + } + + @Test + void can_explain_nested() { + Set nestedOperatorArgs = Set.of("message.info", "message"); + Map> groupedFieldsByPath = + Map.of("message", List.of("message.info")); + PhysicalPlan plan = nested(tableScan, nestedOperatorArgs, groupedFieldsByPath); + + assertEquals( + new ExplainResponse( + new ExplainResponseNode( + "NestedOperator", + Map.of("nested", Set.of("message.info", "message")), singletonList(tableScan.explainNode()))), explain.apply(plan) ); @@ -246,7 +263,7 @@ public String toString() { public ExplainResponseNode explainNode() { return new ExplainResponseNode( "FakeTableScan", - ImmutableMap.of("request", "Fake DSL request"), + Map.of("request", "Fake DSL request"), emptyList()); }