获取apache以正确的格式激发数据帧

时间:2016-03-15 19:44:23

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

我正在尝试将某些输入转换为我想要的格式数据帧中的格式。 我输入的是一个这个案例类的序列,最多有10,000,000个类(或者在将它转换为case类之前可能还有Json字符串..):

case class Element(paramName: String, value: Int, time: Int)

结果我想要一个这样的数据帧:

|Time | ParamA | ParamB | ParamC | Param 10,000 |  
|1000 | 432432 | 8768768 | Null....... | 75675678622 |  
|2000 | Null.......| Null.........| 734543 | Null................. |  

....
因此,不必为所有时隙定义每个参数。缺少的值应该用Null填充。并且可能会有10,000个参数和大约1000个时隙。

我现在的做法似乎从效率来看非常糟糕:

case class Elements(name: String, value: Int, time: Int)

case class GroupedObjects(time: Int, params: (String, Int)*)

 //elements contains the seq of Element
val elementsRdd: RDD[Elements] = sc.parallelize(elements)
val groupedRDD: RDD[GroupedObjects] = elementsRdd
  .groupBy(element => element.time)
  .map(tuple => GroupedObjects(tuple._1, tuple._2.map(element =>
    (element.name, element.value)).toSeq: _*))

//transforming back to json string to get right format for RDD
val jsonRDD: RDD[String] = groupedRDD.map { obj =>
  "{\"time\":" + obj.time + obj.params.map(tuple => 
     ",\"" + tuple._1 + "\":" + tuple._2).reduce(_ + _) + "}"
}
val df = sqlContext.read.json(jsonRDD).orderBy("time")
df.show(10)

我在这里看到的问题肯定是更改回String,只能以正确的格式再次读取它。如果有任何帮助向我展示如何以所需的数据帧格式获取输入案例类,我将非常高兴 按照我现在这样做的方式,它非常慢,我得到10,000,000输入行的堆大小异常。

2 个答案:

答案 0 :(得分:2)

从Spark 1.6开始,有一个pivot功能。它适用于DataFrames。由于您使用的是案例类,因此这很简单:

val elementsRdd: RDD[Elements] = sc.parallelize(elements)
val elementsDF = elementsRdd.toDF()

然后你可以这样做:

elementsDF.groupBy($"time").pivot(...)

有关pivot()的更多信息,请参阅GroupedData的文档,但这应该足以让您继续。

答案 1 :(得分:2)

您可能尝试构建Row对象并手动定义RDD架构,如下例所示:

// These extra imports will be required if you don't have them already
import org.apache.spark.sql.Row
import org.apache.spark.sql.types.{IntegerType, StructField, StructType}

//elements contains the seq of Element
val elementsRdd = sc.parallelize(elements)

val columnNames = elementsRdd.map(_.name).distinct().collect().sorted

val pivoted = elementsRdd.groupBy(_.time).map {
  case (time, elemsByTime) =>
    val valuesByColumnName = elemsByTime.groupBy(_.name).map {
      case (name, elemsByTimeAndName) => (name, elemsByTimeAndName.map(_.value).sum)
    }
    val allValuesForRow = columnNames.map(valuesByColumnName.getOrElse(_, null))
    (time, allValuesForRow)
}

val schema = StructType(StructField("Time", IntegerType) :: columnNames.map(columnName => StructField(columnName, IntegerType, nullable = true)).toList)
val rowRDD = pivoted.map(p => Row.fromSeq(p._1 :: p._2.toList))
val df = sqlContext.createDataFrame(rowRDD, schema)
df.show(10)

我在本地试用了10,000,000个这样的元素:

val elements = (1 to 10000000).map(i => Element("Param" + (i % 1000).toString, i + 100, i % 10000))

它在合理的时间内成功完成。