Skip to content

Commit 98516d6

Browse files
authored
Support read multi-values from OpenSearch if no codegen triggered (#5015)
* Support read multi-values from OpenSearch Signed-off-by: Lantao Jin <ltjin@amazon.com> * Fix tests Signed-off-by: Lantao Jin <ltjin@amazon.com> * remove reflection way Signed-off-by: Lantao Jin <ltjin@amazon.com> --------- Signed-off-by: Lantao Jin <ltjin@amazon.com>
1 parent b66dc12 commit 98516d6

6 files changed

Lines changed: 115 additions & 189 deletions

File tree

core/src/main/java/org/opensearch/sql/data/model/ExprValueUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ public static ExprValue fromObjectValue(Object o) {
116116
if (null == o) {
117117
return LITERAL_NULL;
118118
}
119-
if (o instanceof Map) {
119+
if (o instanceof ExprValue) {
120+
return (ExprValue) o;
121+
} else if (o instanceof Map) {
120122
return tupleValue((Map) o);
121123
} else if (o instanceof List) {
122124
return collectionValue(((List) o));

core/src/test/java/org/opensearch/sql/data/model/ExprValueUtilsTest.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,8 @@ public void unSupportedObject() {
218218
Exception exception =
219219
assertThrows(
220220
ExpressionEvaluationException.class,
221-
() -> ExprValueUtils.fromObjectValue(integerValue(1)));
222-
assertEquals(
223-
"unsupported object " + "class org.opensearch.sql.data.model.ExprIntegerValue",
224-
exception.getMessage());
221+
() -> ExprValueUtils.fromObjectValue(new Object()));
222+
assertEquals("unsupported object class java.lang.Object", exception.getMessage());
225223
}
226224

227225
@Test

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,8 @@ public void testNumericLiteral() throws IOException {
600600
schema("floatLiteral", "float"));
601601
verifyDataRows(
602602
result,
603-
rows("hello", 20, 0.05, 0.049999999999999996, 0.05),
604-
rows("world", 30, 0.05, 0.049999999999999996, 0.05));
603+
rows("hello", 20, 0.05, 0.049999999999999996, 0.049999999999999996),
604+
rows("world", 30, 0.05, 0.049999999999999996, 0.049999999999999996));
605605
}
606606

607607
@Test
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
setup:
2+
- do:
3+
indices.create:
4+
index: array-test
5+
body:
6+
settings:
7+
number_of_shards: 1
8+
mappings:
9+
properties:
10+
array_keyword:
11+
type: keyword
12+
array_text:
13+
type: text
14+
array_num:
15+
type: long
16+
array_boolean:
17+
type: boolean
18+
array_date:
19+
type: date
20+
num:
21+
type: integer
22+
parent:
23+
type: object
24+
properties:
25+
child_array_num:
26+
type: float
27+
child_array_keyword:
28+
type: keyword
29+
child_num:
30+
type: integer
31+
- do:
32+
bulk:
33+
index: array-test
34+
refresh: true
35+
body:
36+
- '{"index": {}}'
37+
- '{"array_text": ["Jane Smith","hello world"],"array_keyword": [ "c++", "java" ],"array_num": [1, 2],"array_boolean": [true, false],"array_date": ["2023-01-02T22:03:34.000Z","2023-01-02T22:03:35.000Z"],"num" : 10,"parent": {"child_array_num": [1.1, 2.2], "child_array_keyword":["a a a", "b b b"], "child_num": 100}}'
38+
- '{"index": {}}'
39+
- '{"array_text": "OpenSearch PPL","array_keyword": "python","array_num": 3,"array_boolean": true,"array_date": "2023-01-02T22:03:36.000Z","num" : 11,"parent": {"child_array_num": 3.3, "child_array_keyword":"c c c", "child_num": 101}}'
40+
- do:
41+
query.settings:
42+
body:
43+
transient:
44+
plugins.calcite.enabled : true
45+
---
46+
teardown:
47+
- do:
48+
query.settings:
49+
body:
50+
transient:
51+
plugins.calcite.enabled : false
52+
53+
---
54+
"Handle multiple values (array) documents":
55+
- skip:
56+
features:
57+
- headers
58+
- allowed_warnings
59+
- do:
60+
allowed_warnings:
61+
- 'Loading the fielddata on the _id field is deprecated and will be removed in future versions. If you require sorting or aggregating on this field you should also include the id in the body of your documents, and map this field as a keyword field that has [doc_values] enabled'
62+
headers:
63+
Content-Type: 'application/json'
64+
ppl:
65+
body:
66+
query: 'source=array-test '
67+
- match: {"total": 2}
68+
- match: {"schema": [{"name": "parent", "type": "struct"},{"name":"array_boolean","type":"boolean"},{"name":"array_num","type":"bigint"},{"name":"array_date","type":"timestamp"},{"name":"num","type":"int"},{"name":"array_text","type":"string"},{"name":"array_keyword","type":"string"}]}
69+
- match: {"datarows": [[{"child_array_keyword":["a a a","b b b"],"child_num":100,"child_array_num":[1.1,2.2]},[true, false],[1,2],["2023-01-02 22:03:34","2023-01-02 22:03:35"],10,["Jane Smith","hello world"],["c++","java"]],[{"child_num": 101,"child_array_keyword":"c c c","child_array_num":3.3},true,3,"2023-01-02 22:03:36",11,"OpenSearch PPL","python"]]}

opensearch/src/main/java/org/opensearch/sql/opensearch/executor/OpenSearchExecutionEngine.java

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.sql.ResultSetMetaData;
1212
import java.sql.SQLException;
1313
import java.util.ArrayList;
14+
import java.util.HashMap;
1415
import java.util.LinkedHashMap;
1516
import java.util.List;
1617
import java.util.Map;
@@ -34,6 +35,7 @@
3435
import org.apache.calcite.sql.validate.SqlUserDefinedFunction;
3536
import org.apache.logging.log4j.LogManager;
3637
import org.apache.logging.log4j.Logger;
38+
import org.locationtech.jts.geom.Point;
3739
import org.opensearch.sql.ast.statement.Explain.ExplainFormat;
3840
import org.opensearch.sql.calcite.CalcitePlanContext;
3941
import org.opensearch.sql.calcite.utils.CalciteToolsHelper.OpenSearchRelRunners;
@@ -42,6 +44,7 @@
4244
import org.opensearch.sql.common.response.ResponseListener;
4345
import org.opensearch.sql.data.model.ExprTupleValue;
4446
import org.opensearch.sql.data.model.ExprValue;
47+
import org.opensearch.sql.data.model.ExprValueUtils;
4548
import org.opensearch.sql.data.type.ExprCoreType;
4649
import org.opensearch.sql.data.type.ExprType;
4750
import org.opensearch.sql.executor.ExecutionContext;
@@ -52,10 +55,10 @@
5255
import org.opensearch.sql.expression.function.BuiltinFunctionName;
5356
import org.opensearch.sql.expression.function.PPLFuncImpTable;
5457
import org.opensearch.sql.opensearch.client.OpenSearchClient;
58+
import org.opensearch.sql.opensearch.data.value.OpenSearchExprGeoPointValue;
5559
import org.opensearch.sql.opensearch.executor.protector.ExecutionProtector;
5660
import org.opensearch.sql.opensearch.functions.DistinctCountApproxAggFunction;
5761
import org.opensearch.sql.opensearch.functions.GeoIpFunction;
58-
import org.opensearch.sql.opensearch.util.JdbcOpenSearchDataTypeConvertor;
5962
import org.opensearch.sql.planner.physical.PhysicalPlan;
6063
import org.opensearch.sql.storage.TableScanOperator;
6164
import org.opensearch.transport.client.node.NodeClient;
@@ -212,6 +215,38 @@ public void execute(
212215
});
213216
}
214217

218+
/**
219+
* Process values recursively, handling geo points and nested maps. Geo points are converted to
220+
* OpenSearchExprGeoPointValue. Maps are recursively processed to handle nested structures.
221+
*/
222+
private static Object processValue(Object value) {
223+
if (value == null) {
224+
return null;
225+
}
226+
if (value instanceof Point) {
227+
Point point = (Point) value;
228+
return new OpenSearchExprGeoPointValue(point.getY(), point.getX());
229+
}
230+
if (value instanceof Map) {
231+
Map<String, Object> map = (Map<String, Object>) value;
232+
Map<String, Object> convertedMap = new HashMap<>();
233+
for (Map.Entry<String, Object> entry : map.entrySet()) {
234+
convertedMap.put(entry.getKey(), processValue(entry.getValue()));
235+
}
236+
return convertedMap;
237+
}
238+
if (value instanceof List) {
239+
List<Object> list = (List<Object>) value;
240+
List<Object> convertedList = new ArrayList<>();
241+
for (Object item : list) {
242+
convertedList.add(processValue(item));
243+
}
244+
return convertedList;
245+
}
246+
// For other types, return as-is
247+
return value;
248+
}
249+
215250
private void buildResultSet(
216251
ResultSet resultSet,
217252
RelDataType rowTypes,
@@ -230,11 +265,9 @@ private void buildResultSet(
230265
// Loop through each column
231266
for (int i = 1; i <= columnCount; i++) {
232267
String columnName = metaData.getColumnName(i);
233-
int sqlType = metaData.getColumnType(i);
234-
RelDataType fieldType = fieldTypes.get(i - 1);
235-
ExprValue exprValue =
236-
JdbcOpenSearchDataTypeConvertor.getExprValueFromSqlType(
237-
resultSet, i, sqlType, fieldType, columnName);
268+
Object value = resultSet.getObject(columnName);
269+
Object converted = processValue(value);
270+
ExprValue exprValue = ExprValueUtils.fromObjectValue(converted);
238271
row.put(columnName, exprValue);
239272
}
240273
values.add(ExprTupleValue.fromExprValueMap(row));

opensearch/src/main/java/org/opensearch/sql/opensearch/util/JdbcOpenSearchDataTypeConvertor.java

Lines changed: 0 additions & 176 deletions
This file was deleted.

0 commit comments

Comments
 (0)