This is an automated email from the ASF dual-hosted git repository.
karan pushed a commit to branch 36.0.0
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/36.0.0 by this push:
new 8216487f200 fix json column isNumeric check to properly consider array
element selector types (#18948) (#18951)
8216487f200 is described below
commit 8216487f200beab720e1fafbc651a7a0ad07c2a8
Author: Clint Wylie <[email protected]>
AuthorDate: Mon Jan 26 21:37:45 2026 -0800
fix json column isNumeric check to properly consider array element selector
types (#18948) (#18951)
---
.../druid/msq/exec/MSQComplexGroupByTest.java | 6 ++---
.../nested/CompressedNestedDataComplexColumn.java | 15 ++++++++++-
.../segment/virtual/NestedFieldVirtualColumn.java | 22 ++++++++++-----
.../query/groupby/NestedGroupByArrayQueryTest.java | 30 +++++++++++++++++++++
.../druid/query/scan/NestedDataScanQueryTest.java | 2 +-
.../timeseries/NestedDataTimeseriesQueryTest.java | 31 ++++++++++++++++++++++
.../test/resources/nested-all-types-test-data.json | 2 +-
.../sql/calcite/CalciteNestedDataQueryTest.java | 2 +-
8 files changed, 97 insertions(+), 13 deletions(-)
diff --git
a/multi-stage-query/src/test/java/org/apache/druid/msq/exec/MSQComplexGroupByTest.java
b/multi-stage-query/src/test/java/org/apache/druid/msq/exec/MSQComplexGroupByTest.java
index 274eb0027c4..79de012a3e7 100644
---
a/multi-stage-query/src/test/java/org/apache/druid/msq/exec/MSQComplexGroupByTest.java
+++
b/multi-stage-query/src/test/java/org/apache/druid/msq/exec/MSQComplexGroupByTest.java
@@ -178,7 +178,7 @@ public class MSQComplexGroupByTest extends MSQTestBase
"y", 1.1,
"z", List.of(2, 4, 6)
),
- "c", List.of("a", "b"),
+ "c", List.of("a", "123"),
"v", Collections.emptyList()
)
),
@@ -313,7 +313,7 @@ public class MSQComplexGroupByTest extends MSQTestBase
"y", 1.1,
"z", List.of(2, 4, 6)
),
- "c", List.of("a", "b"),
+ "c", List.of("a", "123"),
"v", Collections.emptyList()
)
),
@@ -435,7 +435,7 @@ public class MSQComplexGroupByTest extends MSQTestBase
.setQueryContext(context)
.setExpectedResultRows(List.of(
new
Object[]{"{\"a\":600,\"b\":{\"x\":\"f\",\"y\":1.1,\"z\":[6,7,8,9]},\"c\":12.3,\"v\":\"b\"}"},
- new
Object[]{"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"c\":[\"a\",\"b\"],\"v\":[]}"},
+ new
Object[]{"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"c\":[\"a\",\"123\"],\"v\":[]}"},
new
Object[]{"{\"a\":400,\"b\":{\"x\":\"d\",\"y\":1.1,\"z\":[3,4]},\"c\":{\"a\":1},\"v\":[]}"},
new
Object[]{"{\"a\":500,\"b\":{\"x\":\"e\",\"z\":[1,2,3,4]},\"c\":\"hello\",\"v\":\"a\"}"},
new
Object[]{"{\"a\":700,\"b\":{\"x\":\"g\",\"y\":1.1,\"z\":[9,null,9,9]},\"c\":null,\"v\":[]}"},
diff --git
a/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
b/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
index 99dccbe81db..f452178b262 100644
---
a/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
+++
b/processing/src/main/java/org/apache/druid/segment/nested/CompressedNestedDataComplexColumn.java
@@ -49,6 +49,7 @@ import org.apache.druid.segment.column.ColumnIndexSupplier;
import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.DictionaryEncodedColumn;
import org.apache.druid.segment.column.StringEncodingStrategies;
+import org.apache.druid.segment.column.TypeSignature;
import org.apache.druid.segment.column.TypeStrategies;
import org.apache.druid.segment.column.TypeStrategy;
import org.apache.druid.segment.column.ValueType;
@@ -1043,8 +1044,20 @@ public abstract class
CompressedNestedDataComplexColumn<TKeyDictionary extends I
if (field instanceof NestedField) {
final NestedField nestedField = (NestedField) field;
return getColumnHolder(nestedField.fieldName,
nestedField.fieldIndex).getCapabilities().isNumeric();
+ } else if (field instanceof NestedArrayElement) {
+ final NestedArrayElement element = (NestedArrayElement) field;
+ final TypeSignature<ValueType> elementType = getColumnHolder(
+ element.nestedField.fieldName,
+ element.nestedField.fieldIndex
+ ).getCapabilities().getElementType();
+ if (elementType != null) {
+ return elementType.isNumeric();
+ }
+ // if element type is null, the field was not an array, so don't
consider it as numeric
+ return false;
}
- return true;
+ // a non-existent field can be considered numeric via a nil selector
+ return field == null;
}
@SuppressWarnings("unchecked")
diff --git
a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java
b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java
index 185a1a3ad9e..8ffde9a4f66 100644
---
a/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java
+++
b/processing/src/main/java/org/apache/druid/segment/virtual/NestedFieldVirtualColumn.java
@@ -411,7 +411,17 @@ public class NestedFieldVirtualColumn implements
VirtualColumn
if (elementNumber < 0) {
throw new IAE("Cannot make array element selector, negative array
index not supported");
}
- return new ArrayElementColumnValueSelector(arraySelector, elementNumber);
+ final ColumnValueSelector<?> elementSelector = new
ArrayElementColumnValueSelector(arraySelector, elementNumber);
+ final ColumnType fieldType = (ColumnType)
arrayColumn.getLogicalType().getElementType();
+ if (fieldType != null && fieldSpec.expectedType != null &&
!fieldSpec.expectedType.equals(fieldType)) {
+ return ExpressionSelectors.castColumnValueSelector(
+ offset::getOffset,
+ elementSelector,
+ fieldType,
+ fieldSpec.expectedType
+ );
+ }
+ return elementSelector;
}
if (holder.getCapabilities().isArray() ||
ColumnType.NESTED_DATA.equals(holder.getCapabilities().toColumnType())) {
@@ -1260,11 +1270,11 @@ public class NestedFieldVirtualColumn implements
VirtualColumn
longs[i] = n.longValue();
nulls[i] = false;
} else {
- Double d = anArray[elementNumber] instanceof String
- ? Doubles.tryParse((String) anArray[elementNumber])
- : null;
- if (d != null) {
- longs[i] = d.longValue();
+ Number number = anArray[elementNumber] instanceof String
+ ? ExprEval.computeNumber((String)
anArray[elementNumber])
+ : null;
+ if (number != null) {
+ longs[i] = number.longValue();
nulls[i] = false;
} else {
longs[i] = 0L;
diff --git
a/processing/src/test/java/org/apache/druid/query/groupby/NestedGroupByArrayQueryTest.java
b/processing/src/test/java/org/apache/druid/query/groupby/NestedGroupByArrayQueryTest.java
index c9685eb5b7c..b39b850c9a3 100644
---
a/processing/src/test/java/org/apache/druid/query/groupby/NestedGroupByArrayQueryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/groupby/NestedGroupByArrayQueryTest.java
@@ -497,6 +497,36 @@ public class NestedGroupByArrayQueryTest
);
}
+ @Test
+ public void testGroupByRootArrayVariantElementLong()
+ {
+ GroupByQuery groupQuery = GroupByQuery.builder()
+ .setDataSource("test_datasource")
+ .setGranularity(Granularities.ALL)
+ .setInterval(Intervals.ETERNITY)
+
.setDimensions(DefaultDimensionSpec.of("v0", ColumnType.LONG))
+ .setVirtualColumns(
+ new NestedFieldVirtualColumn(
+ "arrayVariant",
+ "$[1]",
+ "v0",
+ ColumnType.LONG
+ )
+ )
+ .setAggregatorSpecs(new
CountAggregatorFactory("count"))
+ .setContext(getContext())
+ .build();
+
+
+ runResults(
+ groupQuery,
+ ImmutableList.of(
+ new Object[]{null, 20L},
+ new Object[]{1L, 8L}
+ )
+ );
+ }
+
private void runResults(
GroupByQuery groupQuery,
List<Object[]> expectedResults
diff --git
a/processing/src/test/java/org/apache/druid/query/scan/NestedDataScanQueryTest.java
b/processing/src/test/java/org/apache/druid/query/scan/NestedDataScanQueryTest.java
index 766131ce1e2..bb225eb06a1 100644
---
a/processing/src/test/java/org/apache/druid/query/scan/NestedDataScanQueryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/scan/NestedDataScanQueryTest.java
@@ -606,7 +606,7 @@ public class NestedDataScanQueryTest extends
InitializedNullHandlingTest
Assert.assertEquals(1, resultsRealtime.size());
Assert.assertEquals(resultsRealtime.size(), resultsSegments.size());
Assert.assertEquals(
- "[[1672531200000, null, null, null, 1, 51, -0.13, 1, [], [51, -35],
{a=700, b={x=g, y=1.1, z=[9, null, 9, 9]}, c=null, v=[]}, {x=400, y=[{l=[null],
m=100, n=5}, {l=[a, b, c], m=a, n=1}], z={}}, null, [a, b], null, [2, 3], null,
[null], null, [1, 0, 1], null, [{x=1}, {x=2}], null, hello, 1234, 1.234, {x=1,
y=hello, z={a=1.1, b=1234, c=[a, b, c], d=[]}}, [a, b, c], [1, 2, 3], [1.1,
2.2, 3.3], [], {}, [null, null], [{}, {}, {}], [{a=b, x=1, y=1.3}], 1],
[1672531200000, , 2, null, 0, [...]
+ "[[1672531200000, null, null, null, 1, 51, -0.13, 1, [], [51, -35],
{a=700, b={x=g, y=1.1, z=[9, null, 9, 9]}, c=null, v=[]}, {x=400, y=[{l=[null],
m=100, n=5}, {l=[a, b, c], m=a, n=1}], z={}}, null, [a, b], null, [2, 3], null,
[null], null, [1, 0, 1], null, [{x=1}, {x=2}], null, hello, 1234, 1.234, {x=1,
y=hello, z={a=1.1, b=1234, c=[a, b, c], d=[]}}, [a, b, c], [1, 2, 3], [1.1,
2.2, 3.3], [], {}, [null, null], [{}, {}, {}], [{a=b, x=1, y=1.3}], 1],
[1672531200000, , 2, null, 0, [...]
resultsSegments.get(0).getEvents().toString()
);
Assert.assertEquals(resultsRealtime.get(0).getEvents().toString(),
resultsSegments.get(0).getEvents().toString());
diff --git
a/processing/src/test/java/org/apache/druid/query/timeseries/NestedDataTimeseriesQueryTest.java
b/processing/src/test/java/org/apache/druid/query/timeseries/NestedDataTimeseriesQueryTest.java
index 7e3269fe5d2..34184d7774f 100644
---
a/processing/src/test/java/org/apache/druid/query/timeseries/NestedDataTimeseriesQueryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/timeseries/NestedDataTimeseriesQueryTest.java
@@ -653,6 +653,37 @@ public class NestedDataTimeseriesQueryTest extends
InitializedNullHandlingTest
);
}
+ @Test
+ public void testSumArrayElement()
+ {
+ TimeseriesQuery query = Druids.newTimeseriesQueryBuilder()
+ .dataSource("test_datasource")
+
.intervals(Collections.singletonList(Intervals.ETERNITY))
+ .aggregators(
+ new CountAggregatorFactory("count"),
+ new
LongSumAggregatorFactory("sumNestedVariantNumericArrayElement", "v0")
+ )
+ .virtualColumns(
+ new NestedFieldVirtualColumn("obj",
"$.c[1]", "v0", ColumnType.LONG)
+ )
+ .context(getContext())
+ .build();
+ runResults(
+ query,
+ ImmutableList.of(
+ new Result<>(
+ DateTimes.of("2023-01-01T00:00:00.000Z"),
+ new TimeseriesResultValue(
+ ImmutableMap.<String, Object>builder()
+ .put("count", 14L)
+ .put("sumNestedVariantNumericArrayElement",
246L)
+ .build()
+ )
+ )
+ )
+ );
+ }
+
private void runResults(
TimeseriesQuery timeseriesQuery,
diff --git a/processing/src/test/resources/nested-all-types-test-data.json
b/processing/src/test/resources/nested-all-types-test-data.json
index e8d4a4ac26e..ea1bd98a7dc 100644
--- a/processing/src/test/resources/nested-all-types-test-data.json
+++ b/processing/src/test/resources/nested-all-types-test-data.json
@@ -1,5 +1,5 @@
{"timestamp": "2023-01-01T00:00:00", "str":"a", "long":1, "double":1.0,
"bool": true, "variant": 1, "variantNumeric": 1,
"variantEmptyObj":1, "variantEmtpyArray":1, "variantWithArrays": 1,
"obj":{"a": 100, "b": {"x": "a", "y": 1.1, "z": [1, 2, 3, 4]}, "c": [100], "v":
[]}, "complexObj":{"x": 1234, "y": [{"l": ["a", "b", "c"], "m": "a", "n":
1},{"l": ["a", "b", "c"], "m": "a", "n": 1}], "z": {"a": [1.1, 2.2, 3.3], "b":
true}}, "arrayString": ["a", "b"], [...]
-{"timestamp": "2023-01-01T00:00:00", "str":"", "long":2,
"bool": false, "variant": "b", "variantNumeric": 1.1,
"variantEmptyObj":"b", "variantEmtpyArray":2, "variantWithArrays": "b",
"obj":{"a": 200, "b": {"x": "b", "y": 1.1, "z": [2, 4, 6]}, "c": ["a", "b"],
"v": []}, "complexObj":{"x": 10, "y": [{"l": ["b", "b", "c"], "m": "b", "n":
2}, [1, 2, 3]], "z": {"a": [5.5], "b": false}},
"arrayString": ["a", "b", "c"] [...]
+{"timestamp": "2023-01-01T00:00:00", "str":"", "long":2,
"bool": false, "variant": "b", "variantNumeric": 1.1,
"variantEmptyObj":"b", "variantEmtpyArray":2, "variantWithArrays": "b",
"obj":{"a": 200, "b": {"x": "b", "y": 1.1, "z": [2, 4, 6]}, "c": ["a", "123"],
"v": []}, "complexObj":{"x": 10, "y": [{"l": ["b", "b", "c"], "m": "b", "n":
2}, [1, 2, 3]], "z": {"a": [5.5], "b": false}},
"arrayString": ["a", "b", "c [...]
{"timestamp": "2023-01-01T00:00:00", "str":"null", "long":3, "double":2.0,
"variant": 3.0, "variantNumeric": 1.0,
"variantEmptyObj":3.3, "variantEmtpyArray":3, "variantWithArrays": 3.0,
"obj":{"a": 300},
"complexObj":{"x": 4.4, "y": [{"l": [], "m": 100, "n": 3},{"l": ["a"]},
{"l": ["b"], "n": []}], "z": {"a": [], "b": true}},
"arrayString": ["b", "c"], [...]
{"timestamp": "2023-01-01T00:00:00", "str":"b", "long":4, "double":3.3,
"bool": true, "variant": "1",
"variantEmptyObj":{}, "variantEmtpyArray":4, "variantWithArrays": "1",
"obj":{"a": 400, "b": {"x": "d", "y": 1.1, "z": [3, 4]}, "c": {"a": 1},"v":
[]}, "complexObj":{"x": 1234, "z": {"a": [1.1, 2.2, 3.3], "b": true}},
"arrayString": ["d", "e"], [...]
{"timestamp": "2023-01-01T00:00:00", "str":"c", "long": null, "double":4.4,
"bool": true, "variant": "hello", "variantNumeric": -1000,
"variantEmptyObj":{}, "variantEmtpyArray":[], "variantWithArrays": "hello",
"obj":{"a": 500, "b": {"x": "e", "z": [1, 2, 3, 4]}, "c": "hello","v": "a"},
"complexObj":{"x": 11, "y": [], "z": {"a": [null], "b": false}},
"arrayString": null, [...]
diff --git
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
index 64c17a82f4d..1ff849b02bf 100644
---
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
+++
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteNestedDataQueryTest.java
@@ -6326,7 +6326,7 @@ public abstract class CalciteNestedDataQueryTest extends
BaseCalciteQueryTest
"\"b\"",
"2",
"b",
-
"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"c\":[\"a\",\"b\"],\"v\":[]}",
+
"{\"a\":200,\"b\":{\"x\":\"b\",\"y\":1.1,\"z\":[2,4,6]},\"c\":[\"a\",\"123\"],\"v\":[]}",
"{\"x\":10,\"y\":[{\"l\":[\"b\",\"b\",\"c\"],\"m\":\"b\",\"n\":2},[1,2,3]],\"z\":{\"a\":[5.5],\"b\":false}}",
"[\"a\",\"b\",\"c\"]",
"[null,\"b\"]",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]