spark.sql("""select get_json_object('{"k":{"value":"abc"}}', '$.*.value') as j""").show()
这会导致 null,而它应该返回“abc”。如果我用
*
替换 k
就可以了。
我知道 JSONPath 支持有限(https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-get_json_object)
但是有没有办法实现这一点,那就是 Spark SQL。
有一个 Spark JIRA“任何在 get_json_object ($..foo) 中不起作用的深度搜索”开放以获取完整的 JsonPath 支持。
在问题得到解决之前,恐怕创建一个使用“通用”JsonPath 实现的 UDF 可能是唯一的选择:
> spark-shell --jars "json-path-2.7.0.jar"
:
scala> import com.jayway.jsonpath.JsonPath
import com.jayway.jsonpath.JsonPath
scala> val r = JsonPath.read[net.minidev.json.JSONArray]("""
| {"k":{"value":"abc"},
| "m":{"value":"def"}}
| ""","$.*.value")
r: net.minidev.json.JSONArray = ["abc","def"]
scala>
这是一个迟到的答案,但可能对未来的访客有用。在撰写本文时,Spark 对 JsonPath 的支持仍然有限,这意味着我们仍然需要一种解决方法。我正在使用 pyspark,但该解决方案应该适用于任何地方。
Spark 中的get_json_object
无法通过通配符解析键值,但我们可以尝试利用 from_json
函数来创建字符串和其他映射或数组的 MAP fn.explode(fn.from_json('value', 'MAP<STRING,MAP<STRING, STRING>>'))
。
与explode一起,您可以将映射解压缩为单独的键列和值列。这是用于测试的片段:
spark.sql("""
select explode(from_json('{"k": {"value":"abc"}}', 'MAP<STRING,MAP<STRING, STRING>>'))
""").show()
Output:
+---+--------------+
|key| value|
+---+--------------+
| k|{value -> abc}|
+---+--------------+