我有一个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"))
}
我当然认为没有比其他选项更具计算价格的选项。
答案 0 :(得分:3)
您的代码的所有版本都是等效的,因为它们在最后生成相同的数据帧并且不会产生任何副作用。似乎存在一些对火花如何起作用的基本误解。 DataFrames不包含任何数据。他们只是一个执行计划。
在学习火花时,我们经常讨论“变形”和“行动”之间的区别。
转换会修改数据,例如filter
,select
,drop
以及修改数据框的任何其他方法。 “转型”做零工作,他们只是建立执行计划。
行动实际上会产生一些明显的效果。这些都是保存到文件,将结果收集到驱动程序或使用foreach消耗数据。只有在调用操作时,才会评估数据框并运行转换。
1GB的数据也非常小,如果您真的需要使用spark,那么您可能会重新考虑这些数据。