如何根据条件将来自一个Spark数据帧的数据嵌套在另一个数据帧中

时间:2017-02-06 04:49:24

标签: scala apache-spark apache-spark-sql spark-dataframe

我有2个数据帧:

val df1 = sc.parallelize(Seq((123, 2.23, 1.12), (234, 2.45, 0.12), (456, 1.112, 0.234))).toDF("objid", "ra", "dec")

val df2 = sc.parallelize(Seq((4567, 123, "name1", "val1"), (2322, 456, "name2", "val2"), (3324, 555, "name3", "val3"), (5556, 123, "name4", "val4"), (3345, 123, "name5", "val5"))).toDF("specid", "objid", "name", "value")

它们如下所示:

df1.show()

+-----+-----+-----+                                                             
|objid|   ra|  dec|
+-----+-----+-----+
|  123| 2.23| 1.12|
|  234| 2.45| 0.12|
|  456|1.112|0.234|
+-----+-----+-----+

df2.show()
+------+-----+-----+-----+
|specid|objid| name|value|
+------+-----+-----+-----+
|  4567|  123|name1| val1|
|  2322|  456|name2| val2|
|  3324|  555|name3| val3|
|  5556|  123|name4| val4|
|  3345|  123|name5| val5|
+------+-----+-----+-----+

现在我想将df2嵌套在df1中作为嵌套列,因此架构应如下所示:

val new_schema = df1.schema.add("specs", df2.schema)

new_schema: org.apache.spark.sql.types.StructType = StructType(StructField(objid,IntegerType,false), StructField(ra,DoubleType,false), StructField(dec,DoubleType,false), StructField(specs,StructType(StructField(specid,IntegerType,false), StructField(objid,IntegerType,false), StructField(name,StringType,true), StructField(value,StringType,true)),true))

我想这样做的原因是因为df1和df2之间存在一对多的关系,这意味着每个objid有超过1个规格。而且我不会只加入这两张桌子。我想要最终联合起来创建一个巨型表,大约有50个表。这些表中的大多数都有1到n个关系,而我正在考虑避免在最终连接结果中出现大量重复行和空单元格的方法。

最终结果如下:

+-----+-----+-----+----------------------+                                                              
|                 |          specs       |
|objid|   ra|  dec| specid| name  | value|
+-----+-----+-----+------+----+-------+  |
|  123| 2.23| 1.12| 4567  | name1 | val1 |
|                 | 5556  | name4 | val4 |
|                 | 3345  | name5 | val5 |
+-----+-----+-----+----------------------+
|  234| 2.45| 0.12|                      |
+-----+-----+-----+----------------------+
|  456|1.112|0.234| 2322  | name2 | val2 |
+-----+-----+-----+----------------------+

我尝试使用.withColumn将列添加到df1,但遇到了错误。

我真正想做的是从条件where df2.objid = df1.objid中选择df2中的所有列以匹配行并将其设为df1中的新列,但我不确定它是否是最好的做法。即便如此,我也不知道该怎么做。

有人可以告诉我怎么做吗?

2 个答案:

答案 0 :(得分:0)

据我所知,您不能在另一个数据框中包含数据框(与RDD的情况相同)。

您需要的是两个数据框之间的连接。您可以执行不同类型的连接并连接两个数据框中的行(这是您在df1中创建嵌套 df2列的位置)

答案 1 :(得分:0)

您需要join两个基于objid列的数据框,如下所示

val join = df1.join(df2, "objid")
join.printSchema()

输出:

root
 |-- objid: integer (nullable = false)
 |-- ra: double (nullable = false)
 |-- dec: double (nullable = false)
 |-- specid: integer (nullable = false)
 |-- name: string (nullable = true)
 |-- value: string (nullable = true)

当我们说

join.show()

输出将是

+-----+-----+-----+------+-----+-----+
|objid|   ra|  dec|specid| name|value|
+-----+-----+-----+------+-----+-----+
|  456|1.112|0.234|  2322|name2| val2|
|  123| 2.23| 1.12|  4567|name1| val1|
+-----+-----+-----+------+-----+-----+

有关详细信息,请查看here

更新

我认为你正在寻找像这样的东西

df1.join(df2, df1("objid") === df2("objid"), "left_outer").show()

,输出为:

+-----+-----+-----+------+-----+-----+-----+
|objid|   ra|  dec|specid|objid| name|value|
+-----+-----+-----+------+-----+-----+-----+
|  456|1.112|0.234|  2322|  456|name2| val2|
|  234| 2.45| 0.12|  null| null| null| null|
|  123| 2.23| 1.12|  4567|  123|name1| val1|
|  123| 2.23| 1.12|  5556|  123|name4| val4|
|  123| 2.23| 1.12|  3345|  123|name5| val5|
+-----+-----+-----+------+-----+-----+-----+