如何将Pyspark Dataframe 中的字典拆分为多行?

igetnqfo  于 2022-12-11  发布在  Spark
关注(0)|答案(1)|浏览(150)

我使用以下命令提取了以下 Dataframe :

extract   = data.select('properties.id', 'flags')

|   id  | flags                      |
|-------| ---------------------------|
| v_001 | "{"93":true,"83":true}"    |
| v_002 | "{"45":true,"76":true}"    |

我想要的结果是:

|   id  | flags |
|-------| ------|
| v_001 | 93    |
| v_001 | 83    |
| v_002 | 45    |
| v_002 | 76    |

我尝试将explode应用为以下形式:

extract   = data.select('properties.id', explode(col('flags')))

但我遇到了以下情况:

cannot resolve 'explode(flags)' due to data type mismatch: input to function explode should be array or map type, not struct<93:boolean,83:boolean,45:boolean,76:boolean>

这是有意义的,因为列的模式与explode函数不兼容。我如何调整函数以获得我想要的结果?有没有更好的方法来解决这个问题?
P.D.:所需的表模式不是最好的设计,但这超出了我的范围,因为这将涉及另一个主题讨论。

yqhsw0fo

yqhsw0fo1#

正如您可能已经看到的,explode需要ArrayType,而您似乎只是从flags中的dict获取密钥。
因此,您可以先将flags转换为MapType,然后使用map_keys将所有密钥提取到列表中。

df.withColumn('flags', F.map_keys(F.from_json('flags', MapType(StringType(), BooleanType()))))

这样就会造成这样的

+-----+--------+
|   id|   flags|
+-----+--------+
|v_001|[93, 83]|
|v_002|[45, 76]|
+-----+--------+

然后,您可以在flags上使用explode
第一次
整个代码

df = (df.withColumn('flags', F.map_keys(F.from_json('flags', MapType(StringType(), BooleanType()))))
      .select('id', F.explode('flags')))

更新

最好提供模式并将标志读作MapType,但如果您的json很复杂,很难创建模式,您可以将struct转换为String一次,然后再转换为MapType

# Add this line before `from_json`
df = df.select('id', F.to_json('flags').alias('flags'))

# Or you can do in 1 shot.
df = (df.withColumn('flags', F.map_keys(F.from_json(F.to_json('flags'), MapType(StringType(), BooleanType()))))
      .select('id', F.explode('flags')))

相关问题