我有一张这样的桌子:
row | key | json
0 | a | {'something':{'a':1}}
1 | b | {'something':{'a':2, 'b':3 }}
我想在key
列中定义的json中检索值:
row | value
0 | 1 // from $.something.a
1 | 3 // from $.something.b
在蜂巢上可以做
select get_json_object(json, concat("$.something.", key) from table;
,它将返回正确的值。但是,在pyspark上,我找不到复制此行为的方法,它似乎无法基于该列构建路径。我尝试过
context.table("table").select(
get_json_object(F.col("json", concat("$something.", F.col("key"))
);
它告诉我“列不可迭代”。但是,仅使用concat可以正常工作:
context.table("table")
.select(
concat("$something.", F.col("key").alias(path)
);
row | path
0 | $.something.a
1 | $.something.b
我能够使用UDF做到这一点,但是有什么方法可以立即使用PySpark完成它?
答案 0 :(得分:1)
当前的spark实现无法提供将第二个参数作为get_json_object
中的列传递的方法(尽管在内部它会将其转换为文字列并使用它。)
我使用UDF实现相同的目的:
我有输入的JSON,而我感兴趣的字段的路径(每个JSON可能不同)来自另一个文件。
创建了一个UDF,它使用两个参数(JSON列和path列)并以JSON形式返回该路径处的字符串值。 `
def getValueFromJson = (json: String, path: String) => {
def getValue(json: JsonNode, strings: Array[String], index: Int): String = {
if (index < strings.length - 1)
getValue(json.path(strings(index).trim), strings, index + 1) //1 //0
else
json.path(strings(index).trim).toString
}
val mapper = new ObjectMapper()
val root: JsonNode = mapper.readTree(json) //c.b
val strings = path.split('.')
val value = getValue(root, strings, 0)
value
}
UDF的用法:
val a = "{ \"id\": 1, \"b\": \"in 1\" }"
val b = "{ \"id\": 2, \"c\": { \"b\": \"in 2\" } }"
val c = "{ \"id\": 3, \"b\": \"in 3\" }"
val d = "{ \"id\": 4, \"f\": { \"a\": \"in 4\" } }"
val ll = List(a, b, c, d)
val path = spark.read.format("com.databricks.spark.csv").option("inferSchema", "true").option("header", "true").load("paths.csv")
import spark.implicits._
val ip = spark.sparkContext.parallelize(ll).toDF
val ipWithId = ip.withColumn("id", get_json_object(col("value"), "$.id").cast("integer"))
val joined = ipWithId.join(path, Seq("id"))
val getValFromJson = spark.udf.register("getjson", getValueFromJson)
val finalDf = joined.withColumn("valfromJson", getValFromJson(col("value"), col("path")))
finalDf.show(false)
Path.csv在哪里:
id,path
1, b
2, c.b
3, b
4, f.a
这是输出:
+---+----------------------------------+----+-----------+
|id |value |path|valfromJson|
+---+----------------------------------+----+-----------+
|1 |{ "id": 1, "b": "in 1" } | b |"in 1" |
|2 |{ "id": 2, "c": { "b": "in 2" } }| c.b|"in 2" |
|3 |{ "id": 3, "b": "in 3" } | b |"in 3" |
|4 |{ "id": 4, "f": { "a": "in 4" } }| f.a|"in 4" |
+---+----------------------------------+----+-----------+