This is an automated email from the ASF dual-hosted git repository. xiangfu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new de8fa0beb6 Support jsonKeyValueArrayToMap function (#15352) de8fa0beb6 is described below commit de8fa0beb61cd91bbe5761bcc4a21efc65f6f0c8 Author: Xiang Fu <xiangfu.1...@gmail.com> AuthorDate: Wed Mar 26 14:42:07 2025 -0700 Support jsonKeyValueArrayToMap function (#15352) --- .../common/function/scalar/JsonFunctions.java | 58 ++++++++++++++++++++++ .../pinot/common/function/JsonFunctionsTest.java | 31 ++++++++++++ 2 files changed, 89 insertions(+) diff --git a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/JsonFunctions.java b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/JsonFunctions.java index 2810419f95..6e93b11e73 100644 --- a/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/JsonFunctions.java +++ b/pinot-common/src/main/java/org/apache/pinot/common/function/scalar/JsonFunctions.java @@ -19,6 +19,8 @@ package org.apache.pinot.common.function.scalar; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.annotations.VisibleForTesting; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; @@ -226,6 +228,62 @@ public class JsonFunctions { } } + /** + * Extract an array of key-value maps to a map. + * E.g. input: [{"key": "k1", "value": "v1"}, {"key": "k2", "value": "v2"}, {"key": "k3", "value": "v3"}] + * output: {"k1": "v1", "k2": "v2", "k3": "v3"} + */ + @ScalarFunction + public static Object jsonKeyValueArrayToMap(Object keyValueArray) { + return jsonKeyValueArrayToMap(keyValueArray, "key", "value"); + } + + @ScalarFunction + public static Object jsonKeyValueArrayToMap(Object keyValueArray, String keyColumnName, String valueColumnName) { + Map<String, String> result = new java.util.HashMap<>(); + if (keyValueArray instanceof Object[]) { + Object[] array = (Object[]) keyValueArray; + for (Object obj : array) { + setValuesToMap(keyColumnName, valueColumnName, obj, result); + } + } else if (keyValueArray instanceof List) { + List<Object> list = (List<Object>) keyValueArray; + for (Object obj : list) { + setValuesToMap(keyColumnName, valueColumnName, obj, result); + } + } else { + ObjectMapper mapper = new ObjectMapper(); + JsonNode arrayNode; + try { + arrayNode = mapper.readTree(keyValueArray.toString()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + for (int i = 0; i < arrayNode.size(); i++) { + JsonNode node = arrayNode.get(i); + result.put(node.get(keyColumnName).asText(), node.get(valueColumnName).asText()); + } + } + return result; + } + + private static void setValuesToMap(String keyColumnName, String valueColumnName, Object obj, + Map<String, String> result) { + if (obj instanceof Map) { + Map<String, String> objMap = (Map) obj; + result.put(objMap.get(keyColumnName), objMap.get(valueColumnName)); + } else { + ObjectMapper mapper = new ObjectMapper(); + JsonNode mapNode; + try { + mapNode = mapper.readTree(obj.toString()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + result.put(mapNode.get(keyColumnName).asText(), mapNode.get(valueColumnName).asText()); + } + } + @VisibleForTesting static class ArrayAwareJacksonJsonProvider extends JacksonJsonProvider { @Override diff --git a/pinot-common/src/test/java/org/apache/pinot/common/function/JsonFunctionsTest.java b/pinot-common/src/test/java/org/apache/pinot/common/function/JsonFunctionsTest.java index 8b28af5fea..c374cfbf1f 100644 --- a/pinot-common/src/test/java/org/apache/pinot/common/function/JsonFunctionsTest.java +++ b/pinot-common/src/test/java/org/apache/pinot/common/function/JsonFunctionsTest.java @@ -401,4 +401,35 @@ public class JsonFunctionsTest { assertFalse(JsonFunctions.jsonPathExists(null, "$.[*].name")); assertFalse(JsonFunctions.jsonPathExists(null, null)); } + + @Test + public void testJsonKeyValueArrayToMap() { + String jsonString = "[" + + "{\"key\": \"k1\", \"value\": \"v1\"}, " + + "{\"key\": \"k2\", \"value\": \"v2\"}, " + + "{\"key\": \"k3\", \"value\": \"v3\"}, " + + "{\"key\": \"k4\", \"value\": \"v4\"}, " + + "{\"key\": \"k5\", \"value\": \"v5\"}" + + "]"; + Map<String, Object> expected = ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3", "k4", "v4", "k5", "v5"); + assertEquals(JsonFunctions.jsonKeyValueArrayToMap(jsonString), expected); + + Object[] jsonArray = new Object[]{ + "{\"key\": \"k1\", \"value\": \"v1\"}", + "{\"key\": \"k2\", \"value\": \"v2\"}", + "{\"key\": \"k3\", \"value\": \"v3\"}", + "{\"key\": \"k4\", \"value\": \"v4\"}", + "{\"key\": \"k5\", \"value\": \"v5\"}" + }; + assertEquals(JsonFunctions.jsonKeyValueArrayToMap(jsonArray), expected); + + List<Object> jsonList = ImmutableList.of( + "{\"key\": \"k1\", \"value\": \"v1\"}", + "{\"key\": \"k2\", \"value\": \"v2\"}", + "{\"key\": \"k3\", \"value\": \"v3\"}", + "{\"key\": \"k4\", \"value\": \"v4\"}", + "{\"key\": \"k5\", \"value\": \"v5\"}" + ); + assertEquals(JsonFunctions.jsonKeyValueArrayToMap(jsonList), expected); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org