如何从分组数据中获取火花数据帧

时间:2016-08-27 04:08:56

标签: scala apache-spark

我有一个数据框,我希望按列进行分组,然后将这些组重新转换为具有相同模式的数据框。原因是我希望在组中映射具有签名DataFrame -> String的函数。以下是我正在尝试的内容:

val df = sc.parallelize(Seq((1,2,3),(1,2,4),(2,3,4))).toDF
val schema = df.schema
val groups = df.rdd.groupBy(x => x(0))
               .mapValues(g => sqlContext.createDataFrame(sc.makeRDD(g.toList), schema))
               .take(1)

这就是我所希望的:

scala> groups(0)._2.collect
Array[org.apache.spark.sql.Row] = Array([1,2,3], [1,2,4])    

但是它没有工作(任务失败了NullPointerException)...我猜你不能映射一个引用火花上下文的函数,但我不知道还有什么其他的实现这个目标?

1 个答案:

答案 0 :(得分:1)

  

我猜你不能映射一个引用火花上下文的函数

正确 - 您不能在传递给任何Spark的高阶函数的函数内使用Spark的任何上下文对象(或RDD或Dataframe),因为这需要序列化这些对象和将它们发送给执行程序,但它们是故意不可序列化的,因为它没有意义(每个执行程序必须表现得像另一个驱动程序应用程序)。

要实现仅包含一个“组”的数据框,我建议您使用filter代替groupBy:您可以先collect所有组密钥,然后将每个组映射到过滤后的Dataframe:

val df = sc.parallelize(Seq((1,2,3),(1,2,4),(2,3,4))).toDF

df.cache() // EDIT: this might speed this up significantly, as DF will be reused instead of recalculated for each key 

val groupKeys: Array[Int] = df.map { case Row(i: Int, _, _) => i }.distinct().collect()
val dfPerKey: Array[DataFrame] = groupKeys.map(k => df.filter($"_1" === k))

dfPerKey.foreach(_.show())
// prints:
//    +---+---+---+
//    | _1| _2| _3|
//    +---+---+---+
//    |  1|  2|  3|
//    |  1|  2|  4|
//    +---+---+---+
//
//    +---+---+---+
//    | _1| _2| _3|
//    +---+---+---+
//    |  2|  3|  4|
//    +---+---+---+