Spark - 从循环中生成的行列表中创建DataFrame

时间:2017-09-07 11:52:32

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

我有一个循环,在每次迭代中生成行。我的目标是创建一个具有给定模式的数据框,该数据框仅包含那些行。我想到了一系列要遵循的步骤,但我无法在每次循环迭代中向Row添加新的List[Row]

我正在尝试以下方法:

var listOfRows = List[Row]()

val dfToExtractValues: DataFrame = ???

dfToExtractValues.foreach { x => 

    //Not really important how to generate here the variables
    //So to simplify all the rows will have the same values

    var col1 = "firstCol"
    var col2 = "secondCol"  
    var col3 = "thirdCol"

    val newRow =  RowFactory.create(col1,col2,col3)

    //This step I am not able to do
    //listOfRows += newRow        -> Just for strings
    //listOfRows.add(newRow)      -> This add doesnt exist, it is a addString
    //listOfRows.aggregate(1)(newRow)       -> This is not how aggreage works...
}


val rdd = sc.makeRDD[RDD](listOfRows)   

val dfWithNewRows = sqlContext.createDataFrame(rdd, myOriginalDF.schema)

有人能告诉我我做错了什么,或者我可以改变从我生成的行生成数据帧的方法中做些什么?

也许有更好的方法来收集行而不是List [Row]。但后来我需要将其他类型的集合转换为数据帧。

1 个答案:

答案 0 :(得分:1)

  

有人可以告诉我,我做错了什么

<强>闭包

首先,您似乎跳过了编程指南中的Understanding Closures。任何修改通过闭包传递的变量的尝试都是徒劳的。您所能做的就是修改副本,更改不会全局反映。

变量不会使对象变为可变:

var listOfRows = List[Row]()

创建一个变量。已分配的List与其一样不可变。如果它不在Spark上下文中,您可以创建一个新的List并重新分配:

listOfRows = newRow :: listOfRows

请注意,我们不会追加 - 您不希望在循环中附加到列表中。

当您想要共享数据时,具有不可变对象的变量很有用(例如,它是Akka中的常见模式),但Spark中没有很多应用程序。

分发内容:

最后,永远不要将数据提取给驱动程序,只是为了再次分发它。您还应避免在RDDsDataFrames之间进行不必要的转换。最好一直使用DataFrame运算符:

dfToExtractValues.select(...)

但如果您需要更复杂的map

import org.apache.spark.sql.catalyst.encoders.RowEncoder

dfToExtractValues.map(x => ...)(RowEncoder(schema))