В 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()