在Spark数据帧字段中创建包含数组中每个结构的第一个元素的数组

时间:2016-12-20 19:46:56

标签: apache-spark pyspark spark-dataframe

如何在PySpark数据帧中从结构数组转到每个结构的第一个元素的数组?

一个例子将使这更清楚。让我们说我的数据框定义如下:

scoresheet = spark.createDataFrame([("Alice", [("Math",100),("English",80)]),("Bob", [("Math", 90)]),("Charlie", [])],["name","scores"])

上面定义的模式和数据框如下所示:

root
 |-- name: string (nullable = true)
 |-- scores: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- _1: string (nullable = true)
 |    |    |-- _2: long (nullable = true)

+-------+--------------------------+
|name   |scores                    |
+-------+--------------------------+
|Alice  |[[Math,100], [English,80]]|
|Bob    |[[Math,90]]               |
|Charlie|[]                        |
+-------+--------------------------+

您可以看到主题标记包含在每个学生的(Subject,Marks)类型的有序结构中。每个学生的科目数不是一成不变的,可能为零。

我想从这里开始创建一个新的数据框,其中只包含每个学生的数组中的主题,没有标记。对于没有科目的学生,它应该产生一个空数组。简而言之,它应该是这样的:

+-------+---------------+
|name   |scores         |
+-------+---------------+
|Alice  |[Math, English]|
|Bob    |[Math]         |
|Charlie|[]             |
+-------+---------------+

请注意,行数与之前相同;所以我不能使用爆炸,除非我之后重新组合,这似乎在计算上效率低下。

2 个答案:

答案 0 :(得分:2)

你能做的最好的是udf:

from pyspark.sql.functions import udf
from pyspark.sql.types import ArrayType, StringType

take_first = udf(lambda rows: [row[0] for row in rows], ArrayType(StringType()))

scoresheet.withColumn("scores", take_first("scores"))

答案 1 :(得分:0)

作为参考,这是具有爆炸,分组依据和聚合的版本。

var result = db.Where(searchDetails.ColName + ".Contains(@0)", searchDetails.SearchVal);

由于这纯粹是在PySpark中进行的,因此在某些情况下如果它比UDF版本快,我不会感到惊讶,但是我没有进行任何分析。左联接是为了确保没有成绩的学生不会落在最终成绩中。