Skip to content

Commit 6d291b8

Browse files
committed
Correct spath's implementation and multiple explain results
Signed-off-by: Yuanchun Shen <yuanchu@amazon.com>
1 parent 568fc00 commit 6d291b8

11 files changed

Lines changed: 81 additions & 54 deletions

File tree

core/src/main/java/org/opensearch/sql/calcite/CalciteRelNodeVisitor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -747,8 +747,8 @@ public RelNode visitTranspose(
747747
.map(
748748
f ->
749749
Map.entry(
750-
ImmutableList.of(rx.makeLiteral(f)),
751-
ImmutableList.of((RexNode) rx.makeCast(varchar, b.field(f), true))))
750+
ImmutableList.of((RexLiteral) rx.makeLiteral(f, varchar, true)),
751+
ImmutableList.of(rx.makeCast(varchar, b.field(f), true, true))))
752752
.collect(Collectors.toList()));
753753

754754
// Step 3: Trim spaces from columnName column before pivot

core/src/main/java/org/opensearch/sql/calcite/DynamicFieldsHelper.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,28 @@ private static RexNode getFieldsAsMap(
290290
List<String> keys = excludeMetaFields(existingFields);
291291
keys.removeAll(excluded);
292292
Collections.sort(keys);
293+
// Handle empty keys case - Calcite ARRAY[] requires at least 1 element
294+
if (keys.isEmpty()) {
295+
return createEmptyMap(context);
296+
}
293297
RexNode keysArray = getStringLiteralArray(keys, context);
294298
List<RexNode> values =
295-
keys.stream().map(key -> context.relBuilder.field(key)).collect(Collectors.toList());
299+
keys.stream()
300+
.map(key -> context.relBuilder.cast(context.relBuilder.field(key), SqlTypeName.VARCHAR))
301+
.collect(Collectors.toList());
296302
RexNode valuesArray = makeArray(values, context);
297303
return context.rexBuilder.makeCall(BuiltinFunctionName.MAP_FROM_ARRAYS, keysArray, valuesArray);
298304
}
299305

306+
/** Create an empty map by casting NULL to MAP type */
307+
private static RexNode createEmptyMap(CalcitePlanContext context) {
308+
RelDataType varcharType =
309+
context.rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR);
310+
RelDataType mapType =
311+
context.rexBuilder.getTypeFactory().createMapType(varcharType, varcharType);
312+
return context.rexBuilder.makeNullLiteral(mapType);
313+
}
314+
300315
/** Create string literal array from collection of strings */
301316
private static RexNode getStringLiteralArray(
302317
Collection<String> keys, CalcitePlanContext context) {

core/src/main/java/org/opensearch/sql/expression/function/PPLBuiltinOperators.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,8 @@ public SqlNode rewriteCall(SqlValidator validator, SqlCall call) {
516516
// it will choose none of them in the end.) Therefore, SPARK functions used are explicitly
517517
// declared here for lookup.
518518
public static final SqlFunction REGEXP = SqlLibraryOperators.REGEXP;
519+
public static final SqlFunction MAP_FROM_ARRAYS = SqlLibraryOperators.MAP_FROM_ARRAYS;
520+
public static final SqlFunction MAP_CONCAT = SqlLibraryOperators.MAP_CONCAT;
519521

520522
/**
521523
* Returns the PPL specific operator table, creating it if necessary.

core/src/main/java/org/opensearch/sql/expression/function/PPLFuncImpTable.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,9 +806,9 @@ void populate() {
806806
registerOperator(MVZIP, PPLBuiltinOperators.MVZIP);
807807
registerOperator(MVMAP, PPLBuiltinOperators.TRANSFORM);
808808
registerOperator(MAP_APPEND, PPLBuiltinOperators.MAP_APPEND);
809-
registerOperator(MAP_CONCAT, SqlLibraryOperators.MAP_CONCAT);
809+
registerOperator(MAP_CONCAT, PPLBuiltinOperators.MAP_CONCAT);
810810
registerOperator(MAP_REMOVE, PPLBuiltinOperators.MAP_REMOVE);
811-
registerOperator(MAP_FROM_ARRAYS, SqlLibraryOperators.MAP_FROM_ARRAYS);
811+
registerOperator(MAP_FROM_ARRAYS, PPLBuiltinOperators.MAP_FROM_ARRAYS);
812812
registerOperator(ARRAY_LENGTH, SqlLibraryOperators.ARRAY_LENGTH);
813813
registerOperator(ARRAY_SLICE, SqlLibraryOperators.ARRAY_SLICE);
814814
registerOperator(FORALL, PPLBuiltinOperators.FORALL);

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLSpathCommandIT.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
package org.opensearch.sql.calcite.remote;
77

8+
import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_LOGS;
89
import static org.opensearch.sql.util.MatcherUtils.rows;
910
import static org.opensearch.sql.util.MatcherUtils.schema;
1011
import static org.opensearch.sql.util.MatcherUtils.verifyDataRows;
12+
import static org.opensearch.sql.util.MatcherUtils.verifyNumOfRows;
1113
import static org.opensearch.sql.util.MatcherUtils.verifySchema;
1214

1315
import java.io.IOException;
@@ -19,6 +21,7 @@ public class CalcitePPLSpathCommandIT extends CalcitePPLSpathTestBase {
1921
public void init() throws Exception {
2022
super.init();
2123
enableCalcite();
24+
loadIndex(Index.LOGS);
2225

2326
putJsonItem(1, "simple", sj("{'a': 1, 'b': 2, 'c': 3}"));
2427
putJsonItem(2, "simple", sj("{'a': 1, 'b': 2, 'c': 3}"));
@@ -154,6 +157,14 @@ public void testSpathWithAbsentField() throws IOException {
154157
verifyDataRows(result, rows("1", null));
155158
}
156159

160+
@Test
161+
public void testSpathWithDynamicFields() throws IOException {
162+
JSONObject result =
163+
executeQuery(source(TEST_INDEX_LOGS, "spath input=message | where status = '200'"));
164+
verifySchema(result, schema("status", "string"));
165+
verifyNumOfRows(result, 0);
166+
}
167+
157168
@Test
158169
public void testOverwrap() throws IOException {
159170
JSONObject result =

integ-test/src/test/resources/expectedOutput/calcite/explain_mvcombine.yaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
calcite:
22
logical: |
33
LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])
4-
LogicalProject(state=[$0], city=[$1], age=[$2])
5-
LogicalAggregate(group=[{0, 1}], age=[ARRAY_AGG($2) FILTER $3])
6-
LogicalProject(state=[$7], city=[$5], age=[$8], $f3=[IS NOT NULL($8)])
7-
CalciteLogicalIndexScan(table=[[OpenSearch, opensearch-sql_test_index_account]])
4+
LogicalAggregate(group=[{0, 1}], age=[ARRAY_AGG($2) FILTER $3])
5+
LogicalProject(state=[$7], city=[$5], age=[$8], $f3=[IS NOT NULL($8)])
6+
CalciteLogicalIndexScan(table=[[OpenSearch, opensearch-sql_test_index_account]])
87
physical: |
98
EnumerableLimit(fetch=[10000])
109
EnumerableAggregate(group=[{0, 1}], age=[ARRAY_AGG($2) FILTER $3])
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
calcite:
22
logical: |
33
LogicalSystemLimit(fetch=[10000], type=[QUERY_SIZE_LIMIT])
4-
LogicalFilter(condition=[=($0, '200')])
5-
LogicalProject(status=[CAST(ITEM(JSON_EXTRACT_ALL($3), 'status')):VARCHAR NOT NULL], _MAP=[map_append(MAP_FROM_ARRAYS(ARRAY('@timestamp', 'created_at', 'level', 'message', 'server'), ARRAY($2, $0, $4, $3, $1)), map_remove(JSON_EXTRACT_ALL($3), ARRAY('status')))])
6-
CalciteLogicalIndexScan(table=[[OpenSearch, opensearch-sql_test_index_logs]])
4+
LogicalProject(status=[$0], _MAP=[$1])
5+
LogicalFilter(condition=[=($0, '200')])
6+
LogicalProject(status=[CAST(ITEM(JSON_EXTRACT_ALL($3), 'status')):VARCHAR], _MAP=[map_append(MAP_FROM_ARRAYS(ARRAY('@timestamp':VARCHAR, 'created_at':VARCHAR, 'level':VARCHAR, 'message':VARCHAR, 'server':VARCHAR), ARRAY(CAST($2):VARCHAR, CAST($0):VARCHAR, $4, $3, $1)), map_remove(JSON_EXTRACT_ALL($3), ARRAY('status':VARCHAR)))])
7+
CalciteLogicalIndexScan(table=[[OpenSearch, opensearch-sql_test_index_logs]])
78
physical: |
8-
EnumerableCalc(expr#0..4=[{inputs}], expr#5=[JSON_EXTRACT_ALL($t0)], expr#6=['status'], expr#7=[ITEM($t5, $t6)], expr#8=[CAST($t7):VARCHAR NOT NULL], expr#9=['@timestamp'], expr#10=['created_at'], expr#11=['level'], expr#12=['message'], expr#13=['server'], expr#14=[ARRAY($t9, $t10, $t11, $t12, $t13)], expr#15=[ARRAY($t1, $t2, $t3, $t0, $t4)], expr#16=[MAP_FROM_ARRAYS($t14, $t15)], expr#17=[ARRAY($t6)], expr#18=[map_remove($t5, $t17)], expr#19=[map_append($t16, $t18)], status=[$t8], _MAP=[$t19])
9-
CalciteEnumerableIndexScan(table=[[OpenSearch, opensearch-sql_test_index_logs]], PushDownContext=[[PROJECT->[message, @timestamp, created_at, level, server], SCRIPT->=(CAST(ITEM(JSON_EXTRACT_ALL($0), 'status')):VARCHAR NOT NULL, '200'), LIMIT->10000], OpenSearchRequestBuilder(sourceBuilder={"from":0,"size":10000,"timeout":"1m","query":{"script":{"script":{"source":"{\"langType\":\"calcite\",\"script\":\"rO0ABXQHkXsKICAib3AiOiB7CiAgICAibmFtZSI6ICI9IiwKICAgICJraW5kIjogIkVRVUFMUyIsCiAgICAic3ludGF4IjogIkJJTkFSWSIKICB9LAogICJvcGVyYW5kcyI6IFsKICAgIHsKICAgICAgIm9wIjogewogICAgICAgICJuYW1lIjogIkNBU1QiLAogICAgICAgICJraW5kIjogIkNBU1QiLAogICAgICAgICJzeW50YXgiOiAiU1BFQ0lBTCIKICAgICAgfSwKICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgIHsKICAgICAgICAgICJvcCI6IHsKICAgICAgICAgICAgIm5hbWUiOiAiSVRFTSIsCiAgICAgICAgICAgICJraW5kIjogIklURU0iLAogICAgICAgICAgICAic3ludGF4IjogIlNQRUNJQUwiCiAgICAgICAgICB9LAogICAgICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgIm9wIjogewogICAgICAgICAgICAgICAgIm5hbWUiOiAiSlNPTl9FWFRSQUNUX0FMTCIsCiAgICAgICAgICAgICAgICAia2luZCI6ICJPVEhFUl9GVU5DVElPTiIsCiAgICAgICAgICAgICAgICAic3ludGF4IjogIkZVTkNUSU9OIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAiZHluYW1pY1BhcmFtIjogMCwKICAgICAgICAgICAgICAgICAgInR5cGUiOiB7CiAgICAgICAgICAgICAgICAgICAgInR5cGUiOiAiVkFSQ0hBUiIsCiAgICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAicHJlY2lzaW9uIjogLTEKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgImNsYXNzIjogIm9yZy5vcGVuc2VhcmNoLnNxbC5leHByZXNzaW9uLmZ1bmN0aW9uLlVzZXJEZWZpbmVkRnVuY3Rpb25CdWlsZGVyJDEiLAogICAgICAgICAgICAgICJ0eXBlIjogewogICAgICAgICAgICAgICAgInR5cGUiOiAiTUFQIiwKICAgICAgICAgICAgICAgICJudWxsYWJsZSI6IHRydWUsCiAgICAgICAgICAgICAgICAia2V5IjogewogICAgICAgICAgICAgICAgICAidHlwZSI6ICJWQVJDSEFSIiwKICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogZmFsc2UsCiAgICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMQogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICJ2YWx1ZSI6IHsKICAgICAgICAgICAgICAgICAgInR5cGUiOiAiQU5ZIiwKICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogZmFsc2UsCiAgICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMSwKICAgICAgICAgICAgICAgICAgInNjYWxlIjogLTIxNDc0ODM2NDgKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJkZXRlcm1pbmlzdGljIjogdHJ1ZSwKICAgICAgICAgICAgICAiZHluYW1pYyI6IGZhbHNlCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAiZHluYW1pY1BhcmFtIjogMSwKICAgICAgICAgICAgICAidHlwZSI6IHsKICAgICAgICAgICAgICAgICJ0eXBlIjogIlZBUkNIQVIiLAogICAgICAgICAgICAgICAgIm51bGxhYmxlIjogdHJ1ZSwKICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0KICAgICAgXSwKICAgICAgInR5cGUiOiB7CiAgICAgICAgInR5cGUiOiAiVkFSQ0hBUiIsCiAgICAgICAgIm51bGxhYmxlIjogZmFsc2UsCiAgICAgICAgInByZWNpc2lvbiI6IC0xCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJkeW5hbWljUGFyYW0iOiAyLAogICAgICAidHlwZSI6IHsKICAgICAgICAidHlwZSI6ICJWQVJDSEFSIiwKICAgICAgICAibnVsbGFibGUiOiB0cnVlLAogICAgICAgICJwcmVjaXNpb24iOiAtMQogICAgICB9CiAgICB9CiAgXQp9\"}","lang":"opensearch_compounded_script","params":{"utcTimestamp": 0,"SOURCES":[0,2,2],"DIGESTS":["message.keyword","status","200"]}},"boost":1.0}},"_source":{"includes":["message","@timestamp","created_at","level","server"],"excludes":[]}}, requestedTotalSize=10000, pageSize=null, startFrom=0)])
9+
EnumerableCalc(expr#0..4=[{inputs}], expr#5=[JSON_EXTRACT_ALL($t0)], expr#6=['status'], expr#7=[ITEM($t5, $t6)], expr#8=[CAST($t7):VARCHAR], expr#9=['@timestamp':VARCHAR], expr#10=['created_at':VARCHAR], expr#11=['level':VARCHAR], expr#12=['message':VARCHAR], expr#13=['server':VARCHAR], expr#14=[ARRAY($t9, $t10, $t11, $t12, $t13)], expr#15=[CAST($t1):VARCHAR], expr#16=[CAST($t2):VARCHAR], expr#17=[ARRAY($t15, $t16, $t3, $t0, $t4)], expr#18=[MAP_FROM_ARRAYS($t14, $t17)], expr#19=['status':VARCHAR], expr#20=[ARRAY($t19)], expr#21=[map_remove($t5, $t20)], expr#22=[map_append($t18, $t21)], status=[$t8], _MAP=[$t22])
10+
CalciteEnumerableIndexScan(table=[[OpenSearch, opensearch-sql_test_index_logs]], PushDownContext=[[PROJECT->[message, @timestamp, created_at, level, server], SCRIPT->=(CAST(ITEM(JSON_EXTRACT_ALL($0), 'status')):VARCHAR, '200'), LIMIT->10000], OpenSearchRequestBuilder(sourceBuilder={"from":0,"size":10000,"timeout":"1m","query":{"script":{"script":{"source":"{\"langType\":\"calcite\",\"script\":\"rO0ABXQHkHsKICAib3AiOiB7CiAgICAibmFtZSI6ICI9IiwKICAgICJraW5kIjogIkVRVUFMUyIsCiAgICAic3ludGF4IjogIkJJTkFSWSIKICB9LAogICJvcGVyYW5kcyI6IFsKICAgIHsKICAgICAgIm9wIjogewogICAgICAgICJuYW1lIjogIkNBU1QiLAogICAgICAgICJraW5kIjogIkNBU1QiLAogICAgICAgICJzeW50YXgiOiAiU1BFQ0lBTCIKICAgICAgfSwKICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgIHsKICAgICAgICAgICJvcCI6IHsKICAgICAgICAgICAgIm5hbWUiOiAiSVRFTSIsCiAgICAgICAgICAgICJraW5kIjogIklURU0iLAogICAgICAgICAgICAic3ludGF4IjogIlNQRUNJQUwiCiAgICAgICAgICB9LAogICAgICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgICAgICB7CiAgICAgICAgICAgICAgIm9wIjogewogICAgICAgICAgICAgICAgIm5hbWUiOiAiSlNPTl9FWFRSQUNUX0FMTCIsCiAgICAgICAgICAgICAgICAia2luZCI6ICJPVEhFUl9GVU5DVElPTiIsCiAgICAgICAgICAgICAgICAic3ludGF4IjogIkZVTkNUSU9OIgogICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgIm9wZXJhbmRzIjogWwogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAiZHluYW1pY1BhcmFtIjogMCwKICAgICAgICAgICAgICAgICAgInR5cGUiOiB7CiAgICAgICAgICAgICAgICAgICAgInR5cGUiOiAiVkFSQ0hBUiIsCiAgICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogdHJ1ZSwKICAgICAgICAgICAgICAgICAgICAicHJlY2lzaW9uIjogLTEKICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIF0sCiAgICAgICAgICAgICAgImNsYXNzIjogIm9yZy5vcGVuc2VhcmNoLnNxbC5leHByZXNzaW9uLmZ1bmN0aW9uLlVzZXJEZWZpbmVkRnVuY3Rpb25CdWlsZGVyJDEiLAogICAgICAgICAgICAgICJ0eXBlIjogewogICAgICAgICAgICAgICAgInR5cGUiOiAiTUFQIiwKICAgICAgICAgICAgICAgICJudWxsYWJsZSI6IHRydWUsCiAgICAgICAgICAgICAgICAia2V5IjogewogICAgICAgICAgICAgICAgICAidHlwZSI6ICJWQVJDSEFSIiwKICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogZmFsc2UsCiAgICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMQogICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICJ2YWx1ZSI6IHsKICAgICAgICAgICAgICAgICAgInR5cGUiOiAiQU5ZIiwKICAgICAgICAgICAgICAgICAgIm51bGxhYmxlIjogZmFsc2UsCiAgICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMSwKICAgICAgICAgICAgICAgICAgInNjYWxlIjogLTIxNDc0ODM2NDgKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICJkZXRlcm1pbmlzdGljIjogdHJ1ZSwKICAgICAgICAgICAgICAiZHluYW1pYyI6IGZhbHNlCiAgICAgICAgICAgIH0sCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAiZHluYW1pY1BhcmFtIjogMSwKICAgICAgICAgICAgICAidHlwZSI6IHsKICAgICAgICAgICAgICAgICJ0eXBlIjogIlZBUkNIQVIiLAogICAgICAgICAgICAgICAgIm51bGxhYmxlIjogdHJ1ZSwKICAgICAgICAgICAgICAgICJwcmVjaXNpb24iOiAtMQogICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgXQogICAgICAgIH0KICAgICAgXSwKICAgICAgInR5cGUiOiB7CiAgICAgICAgInR5cGUiOiAiVkFSQ0hBUiIsCiAgICAgICAgIm51bGxhYmxlIjogdHJ1ZSwKICAgICAgICAicHJlY2lzaW9uIjogLTEKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgImR5bmFtaWNQYXJhbSI6IDIsCiAgICAgICJ0eXBlIjogewogICAgICAgICJ0eXBlIjogIlZBUkNIQVIiLAogICAgICAgICJudWxsYWJsZSI6IHRydWUsCiAgICAgICAgInByZWNpc2lvbiI6IC0xCiAgICAgIH0KICAgIH0KICBdCn0=\"}","lang":"opensearch_compounded_script","params":{"utcTimestamp": 0,"SOURCES":[0,2,2],"DIGESTS":["message.keyword","status","200"]}},"boost":1.0}},"_source":{"includes":["message","@timestamp","created_at","level","server"],"excludes":[]}}, requestedTotalSize=10000, pageSize=null, startFrom=0)])

0 commit comments

Comments
 (0)