如何将嵌套的Struct列展开为多列?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将嵌套的Struct列展开为多列?相关的知识,希望对你有一定的参考价值。

我正在尝试使用嵌套的struct类型(见下文)将DataFrame列扩展为多个列。我正在使用的Struct模式看起来像{"foo": 3, "bar": {"baz": 2}}

理想情况下,我想将上面的内容扩展为两列("foo""bar.baz")。然而,当我尝试使用.select("data.*")(其中data是Struct列)时,我只得到foobar列,其中bar仍然是struct

有没有办法可以扩展两个图层的Struct?

答案

你可以选择data.bar.baz作为bar.baz

df.show()
+-------+
|   data|
+-------+
|[3,[2]]|
+-------+

df.printSchema()
root
 |-- data: struct (nullable = false)
 |    |-- foo: long (nullable = true)
 |    |-- bar: struct (nullable = false)
 |    |    |-- baz: long (nullable = true)

在pyspark:

import pyspark.sql.functions as F
df.select(F.col("data.foo").alias("foo"), F.col("data.bar.baz").alias("bar.baz")).show()
+---+-------+
|foo|bar.baz|
+---+-------+
|  3|      2|
+---+-------+
另一答案

我最终选择了以下函数,以递归方式“展开”分层结构:

从本质上讲,它不断挖掘Struct字段并保持其他字段完整,这种方法消除了当df.select(...)有很多字段时需要非常长的Struct语句。这是代码:

# Takes in a StructType schema object and return a column selector that flattens the Struct
def flatten_struct(schema, prefix=""):
    result = []
    for elem in schema:
        if isinstance(elem.dataType, StructType):
            result += flatten_struct(elem.dataType, prefix + elem.name + ".")
        else:
            result.append(col(prefix + elem.name).alias(prefix + elem.name))
    return result


df = sc.parallelize([Row(r=Row(a=1, b=Row(foo="b", bar="12")))]).toDF()
df.show()
+----------+
|         r|
+----------+
|[1,[12,b]]|
+----------+

df_expanded = df.select("r.*")
df_flattened = df_expanded.select(flatten_struct(df_expanded.schema))

df_flattened.show()
+---+-----+-----+
|  a|b.bar|b.foo|
+---+-----+-----+
|  1|   12|    b|
+---+-----+-----+

以上是关于如何将嵌套的Struct列展开为多列?的主要内容,如果未能解决你的问题,请参考以下文章

展开列数据框嵌套字典

如何将一列拆分为多列

如何将列拆分为具有某些功能的多列?

将多列转换为 Bigquery 中的记录

BigQuery 将新列添加到子查询中的嵌套 STRUCT

物化列:字节为解决 Spark 嵌套列查询性能低下的优化