我正在尝试在Pyspark中实现自定义爆炸。我有4列实际上是具有相同架构的结构数组(一列结构包含的字段比其他三个少)。
对于我DataFrame中的每一行,我有4列是结构数组。这些列是学生,teaching_assantants,老师,管理员。
学生,助教和老师是具有id
,student_level
和name
字段的结构数组。
例如,这是DataFrame中的示例行。
学生,教学助手和教师结构均具有相同的架构(“ id”,“ student_level”,“ name”),而管理员结构具有“ id”和“ name”字段,但缺少学生级别。 / p>
我想执行一个自定义爆炸,以便在每行中,每个学生,助教,教授和管理员都有一个条目以及原始列名,以防万一我必须按“人员类型”进行搜索。 因此,对于上一行的屏幕截图,输出为8行:
+-----------+---------------------+----+---------------+----------+
| School_id | type | id | student_level | name |
+-----------+---------------------+----+---------------+----------+
| 1999 | students | 1 | 0 | Brian |
| 1999 | students | 9 | 2 | Max |
| 1999 | teaching_assistants | 19 | 0 | Xander |
| 1999 | teachers | 21 | 0 | Charlene |
| 1999 | teachers | 12 | 2 | Rob |
| 1999 | administrators | 23 | None | Marsha |
| 1999 | administrators | 11 | None | Ryan |
| 1999 | administrators | 14 | None | Bob |
+-----------+---------------------+----+---------------+----------+
对于管理员来说,student_level列将为空。问题是,如果我使用爆炸功能,最终所有这些项目都放在不同的列中。
是否可以在Pyspark中做到这一点?我曾经想过要弄清楚如何将4个数组列合并为1个数组,然后对该数组进行爆炸,尽管我不确定将结构体数组合并并获取字段名称作为字段是否可行(我已经尝试了各种方法),而且我也不清楚管理员是否缺少字段。
过去,我是通过转换为RDD并使用flatmap /自定义udf来完成此操作的,但对于数百万行而言效率很低。
答案 0 :(得分:2)
想法是使用stack将列students
,teaching_assistants
,teachers
和administrators
转换为单独的行,每个{ {1}}。之后,可以展开包含数据的列,然后将单个结构的元素转换为单独的列。
使用type
要求堆叠的所有列都具有相同的类型。这意味着所有列必须包含相同结构的数组,并且该结构所有元素的可空性必须匹配。因此,stack
列必须首先转换为正确的结构类型。
administrators
打印
df.withColumn("administrators", F.expr("transform(administrators, " +
"a -> if(1<2,named_struct('id', a.id, 'name', a.name, 'student_level', "+
"cast(null as long)),null))"))\
.select("School_id", F.expr("stack(4, 'students', students, "+
"'teaching_assistants', teaching_assistants, 'teachers', teachers, "+
"'administrators', administrators) as (type, temp1)")) \
.withColumn("temp2", F.explode("temp1"))\
.select("School_id", "type", "temp2.id", "temp2.name", "temp2.student_level")\
.show()
第一行看起来很奇怪的+---------+-------------------+---+--------+-------------+
|School_id| type| id| name|student_level|
+---------+-------------------+---+--------+-------------+
| 1999| students| 1| Brian| 0|
| 1999| students| 9| Max| 2|
| 1999|teaching_assistants| 19| Xander| 0|
| 1999| teachers| 21|Charlene| 0|
| 1999| teachers| 12| Rob| 2|
| 1999| administrators| 23| Marsha| null|
| 1999| administrators| 11| Ryan| null|
| 1999| administrators| 14| Bob| null|
+---------+-------------------+---+--------+-------------+
对于为if(1<2, named_struct(...), null)
数组的元素设置正确的空位是必要的。
此解决方案适用于Spark 2.4+。如果可以在上一步中使用transform administrators
结构,则此解决方案也适用于早期版本。