排序嵌套在数组中的结构元素
Ordering struct elements nested in an array
我有一个数组中嵌套结构的模式。我想按字母顺序排列嵌套结构的列。
给出了一个复杂的函数,但它不适用于嵌套在数组中的结构。感谢任何帮助。
我正在使用 PySpark 3.2.1。
我的架构:
root
|-- id: integer (nullable = true)
|-- values: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- Dep: string (nullable = true)
| | |-- ABC: string (nullable = true)
外观应该如何:
root
|-- id: integer (nullable = true)
|-- values: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- ABC: string (nullable = true)
| | |-- Dep: string (nullable = true)
可重现的例子:
data = [
(10, [{"Dep": 10, "ABC": 1}, {"Dep": 10, "ABC": 1}]),
(20, [{"Dep": 20, "ABC": 1}, {"Dep": 20, "ABC": 1}]),
(30, [{"Dep": 30, "ABC": 1}, {"Dep": 30, "ABC": 1}]),
(40, [{"Dep": 40, "ABC": 1}, {"Dep": 40, "ABC": 1}])
]
myschema = StructType(
[
StructField("id", IntegerType(), True),
StructField("values",
ArrayType(
StructType([
StructField("Dep", StringType(), True),
StructField("ABC", StringType(), True)
])
))
]
)
df = spark.createDataFrame(data=data, schema=myschema)
df.printSchema()
df.show(10, False)
我找到了一个非常 hacky 的解决方案,所以如果有人知道更好的解决方案,请成为我的客人添加另一个答案。
- 检索数组[struct]-元素作为它们自己的array-columns
- 以正确的顺序将它们重新压缩为一个结构
代码:
selexpr = ["id", "values.ABC as ABC", "values.Dep as Dep"]
df = df.selectExpr(selexpr)
df = df.withColumn(
"zipped", arrays_zip("ABC", "Dep") # order of the column-names results in ordering!
)
不涵盖所有情况,但作为当前 df 的开始,您可以从内部结构中获取字段列表,对它们进行排序,然后使用 transform
函数更新每个结构元素,如下所示:
from pyspark.sql import functions as F
fields = sorted(df.selectExpr("inline(values)").columns)
df1 = df.withColumn(
"values",
F.transform("values", lambda x: F.struct(*[x[f].alias(f) for f in fields]))
)
df1.printSchema()
#root
# |-- id: integer (nullable = true)
# |-- values: array (nullable = true)
# | |-- element: struct (containsNull = false)
# | | |-- ABC: string (nullable = true)
# | | |-- Dep: string (nullable = true)
我有一个数组中嵌套结构的模式。我想按字母顺序排列嵌套结构的列。
我正在使用 PySpark 3.2.1。
我的架构:
root
|-- id: integer (nullable = true)
|-- values: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- Dep: string (nullable = true)
| | |-- ABC: string (nullable = true)
外观应该如何:
root
|-- id: integer (nullable = true)
|-- values: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- ABC: string (nullable = true)
| | |-- Dep: string (nullable = true)
可重现的例子:
data = [
(10, [{"Dep": 10, "ABC": 1}, {"Dep": 10, "ABC": 1}]),
(20, [{"Dep": 20, "ABC": 1}, {"Dep": 20, "ABC": 1}]),
(30, [{"Dep": 30, "ABC": 1}, {"Dep": 30, "ABC": 1}]),
(40, [{"Dep": 40, "ABC": 1}, {"Dep": 40, "ABC": 1}])
]
myschema = StructType(
[
StructField("id", IntegerType(), True),
StructField("values",
ArrayType(
StructType([
StructField("Dep", StringType(), True),
StructField("ABC", StringType(), True)
])
))
]
)
df = spark.createDataFrame(data=data, schema=myschema)
df.printSchema()
df.show(10, False)
我找到了一个非常 hacky 的解决方案,所以如果有人知道更好的解决方案,请成为我的客人添加另一个答案。
- 检索数组[struct]-元素作为它们自己的array-columns
- 以正确的顺序将它们重新压缩为一个结构
代码:
selexpr = ["id", "values.ABC as ABC", "values.Dep as Dep"]
df = df.selectExpr(selexpr)
df = df.withColumn(
"zipped", arrays_zip("ABC", "Dep") # order of the column-names results in ordering!
)
不涵盖所有情况,但作为当前 df 的开始,您可以从内部结构中获取字段列表,对它们进行排序,然后使用 transform
函数更新每个结构元素,如下所示:
from pyspark.sql import functions as F
fields = sorted(df.selectExpr("inline(values)").columns)
df1 = df.withColumn(
"values",
F.transform("values", lambda x: F.struct(*[x[f].alias(f) for f in fields]))
)
df1.printSchema()
#root
# |-- id: integer (nullable = true)
# |-- values: array (nullable = true)
# | |-- element: struct (containsNull = false)
# | | |-- ABC: string (nullable = true)
# | | |-- Dep: string (nullable = true)