Apache Spark:有效地转换大型DataFrame

时间:2017-11-29 15:40:41

标签: scala apache-spark spark-dataframe

我有一个1GB的csv文件,我使用DataFrame API加载。我还实现了一个自定义Transformer来准备数据,以便Estimator处理它。

transform方法正在执行一些不同的操作:

  • 投射柱。
  • 过滤行。
  • 删除列。
  • 在其他列上创建应用函数的新列。

我担心这个过程中的内存使用情况。如果在每次转换后将结果存储在变量中,会发生什么?例如(简化):

override def transform(dataset: Dataset[_]): DataFrame = {

    val df = dataset.withColumn("DayOfWeek", $"DayOfWeek".cast("int"))

    val df2 = df1.filter($"Diverted" === 0)

    val df3 = df2.drop(forbiddenVariables: _*)

    val df4 = df3.withColumn("DepHour", hourExtractorUdf($"DepTime"))

    val df5 = df4.select($"*", concat($"Origin", lit("-"), $"Dest").as("Route"))

    df5

}

让我们说这是为了在一次转换和另一次转换之间进行记录。

确定。第二种选择。如果我使用var代替val

,该怎么办?
override def transform(dataset: Dataset[_]): DataFrame = {

    var df = dataset.withColumn("DayOfWeek", $"DayOfWeek".cast("int"))

    df = df.filter($"Diverted" === 0)

    df = df.drop(forbiddenVariables: _*)

    df = df.withColumn("DepHour", hourExtractorUdf($"DepTime"))

    df = df.select($"*", concat($"Origin", lit("-"), $"Dest").as("Route"))

    df

}

我想现在我在整个过程中都没有在内存中加载5个DataFrame。正确?

最后,下一个选项是什么,它的内存效率更高吗?

override def transform(dataset: Dataset[_]): DataFrame = {

    dataset.withColumn("DayOfWeek", $"DayOfWeek".cast("int"))
      .filter($"Diverted" === 0)
      .drop(forbiddenVariables: _*)
      .withColumn("DepHour", hourExtractorUdf($"DepTime"))
      .select($"*", concat($"Origin", lit("-"), $"Dest").as("Route"))

}

我当然认为没有比其他选项更具计算价格的选项。

1 个答案:

答案 0 :(得分:3)

您的代码的所有版本都是等效的,因为它们在最后生成相同的数据帧并且不会产生任何副作用。似乎存在一些对火花如何起作用的基本误解。 DataFrames不包含任何数据。他们只是一个执行计划。

在学习火花时,我们经常讨论“变形”和“行动”之间的区别。

转换会修改数据,例如filterselectdrop以及修改数据框的任何其他方法。 “转型”做零工作,他们只是建立执行计划。

另一方面,

行动实际上会产生一些明显的效果。这些都是保存到文件,将结果收集到驱动程序或使用foreach消耗数据。只有在调用操作时,才会评估数据框并运行转换。

1GB的数据也非常小,如果您真的需要使用spark,那么您可能会重新考虑这些数据。