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

Reply via email to