apache-spark - 关系化 json 嵌套数组
问题描述
我有以下目录并想使用 AWS 胶水将其展平?
| accountId | resourceId | items |
|-----------|------------|-----------------------------------------------------------------|
| 1 | r1 | [{name: "tool", version: "1.0"}, {name: "app", version: "1.0"}] |
| 1 | r2 | [{name: "tool", version: "2.0"}, {name: "app", version: "2.0"}] |
| 2 | r3 | [{name: "tool", version: "3.0"}, {name: "app", version: "3.0"}] |
我想将其展平为以下内容:
| accountId | resourceId | name | version |
|-----------|------------|------|---------|
| 1 | r1 | tool | 1.0 |
| 1 | r1 | app | 1.0 |
| 1 | r2 | tool | 2.0 |
| 1 | r2 | app | 2.0 |
| 2 | r3 | tool | 3.0 |
| 2 | r3 | app | 3.0 |
Relationalize.apply
只能展平嵌套项目,它不能带来accountId
结果resourceId
,有没有办法解决这个问题?
解决方案
在 Pyspark 中,如果数组元素的结构是这样的有效 JSON:
{"name": "tool", "version": "1.0"}
您可以使用explode
+from_json
将其解析为struct
.
但在这里你需要做一些清洁。一种方法是在分解列以获取地图列str_to_map
后使用函数。items
然后再次将其分解并旋转以获取地图键作为列。
df = spark.createDataFrame([
(1, "r1", ['{name: "tool", version: "1.0"}', '{name: "app", version: "1.0"}']),
(1, "r2", ['{name: "tool", version: "2.0"}', '{name: "app", version: "2.0"}']),
(2, "r3", ['{name: "tool", version: "3.0"}', '{name: "app", version: "3.0"}'])
], ["accountId", "resourceId", "items"])
# remove leading and trailing {} and convert to map
sql_expr = "str_to_map(trim(BOTH '{}' FROM items), ',', ':')"
df.withColumn("items", explode(col("items"))) \
.select(col("*"), explode(expr(sql_expr))) \
.groupBy("accountId", "resourceId", "items") \
.pivot("key") \
.agg(first(expr("trim(BOTH '\"' FROM trim(value))"))) \
.drop("items")\
.show()
#+---------+----------+--------+----+
#|accountId|resourceId| version|name|
#+---------+----------+--------+----+
#| 1| r1| 1.0| app|
#| 1| r2| 2.0| app|
#| 2| r3| 3.0|tool|
#| 2| r3| 3.0| app|
#| 1| r2| 2.0|tool|
#| 1| r1| 1.0|tool|
#+---------+----------+--------+----+
如果您知道所有键,另一种简单的方法是使用regexp_extract
从字符串中提取值:
df.withColumn("items", explode(col("items"))) \
.withColumn("name", regexp_extract("items", "name: \"(.+?)\"[,}]", 1)) \
.withColumn("version", regexp_extract("items", "version: \"(.+?)\"[,}]", 1)) \
.drop("items") \
.show()
推荐阅读
- node.js - 我在 node.js 中使用的递归方法是否有替代方法?
- wso2 - 在 WSO2 IS + WSO2 APIM 中启动的 DB 脚本
- rust - 为什么 size_of::<&T>() == size_of::
() 取决于 T 是否为 Sized? - bluetooth-lowenergy - 我们可以使用 WireShark 的 BT 数据包日志偷偷 BLE-Mesh-Device 并通过 nRFconnect App 编写嗅探命令吗?
- python - 我将如何编写 Python 脚本来比较两个文件夹并删除两个文件夹中都不存在的文件夹
- sanity - 如何使用算术运算符计算总和
- google-sheets - 如何同时在 2 个谷歌工作表上显示重复项?
- apache-spark - 你如何对 ForeachWriter 实现进行单元测试?
- go - Golang 内置函数“make”如何实现不同类型的参数长度检查?
- javascript - 兄弟姐妹之间的图像轻松交流