2017-09-01 14 views
2

我對Scala很新。我在Java和R的經驗Scala/Spark:不可變數據框和內存

我對數據框和內存管理的不變性感到困惑。原因是這樣的:

R中的Dataframe也是不可變的。隨後,在R中發現它不可行。 (簡單地說)在處理大量列時,每次轉換都會導致新的Dataframe。 1000個連續列上的1000次連續操作將導致1000個Dataframe對象)。現在,大多數數據科學家更喜歡R的data.table,它通過引用在單個data.table對象上執行操作。

斯卡拉的數據框(對一個新手)似乎有一個類似的問題。例如,以下代碼在重命名1000列時似乎會創建1000個數據框。儘管foldLeft(),每次調用withColumn()都會創建一個新的DataFrame實例。

因此,我相信Scala中非常高效的垃圾收集,還是我需要嘗試和限制創建的不可變實例的數量。如果是後者,我應該看什麼技術?

def castAllTypedColumnsTo(df: DataFrame, 
         sourceType: DataType, targetType: DataType): 
DataFrame = 
{ 

val columnsToBeCasted = df.schema 
    .filter(s => s.dataType == sourceType) 

if (columnsToBeCasted.length > 0) 
{ 
    println(s"Found ${columnsToBeCasted.length} columns " + 
    s"(${columnsToBeCasted.map(s => s.name).mkString(",")})" + 
    s" - casting to ${targetType.typeName.capitalize}Type") 
} 

columnsToBeCasted.foldLeft(df) 
{ (foldedDf, col) => 
    castColumnTo(foldedDf, col.name, targetType) 
} 
} 

此方法將返回在每次調用

private def castColumnTo(df: DataFrame, cn: String, tpe: DataType): 
DataFrame = 
{ 

//println("castColumnTo") 
df.withColumn(cn, df(cn).cast(tpe) 

) 
} 

回答

4

一個新實例的區別本質上是懶惰。內存中沒有實現返回的每個新DataFrame。它只存儲基本的DataFrame和應該應用到它的函數。它本質上是一個如何創建一些數據的執行計劃,而不是數據本身。

當需要在某處實際執行並保存結果時,所有1000個操作可以並行應用於每行,因此您可以獲得1個額外的輸出DataFrame。 Spark儘可能地將盡可能多的操作凝聚在一起,並且不會實現任何不必要的或者沒有明確要求保存或緩存的事物。

+0

非常有幫助!所以,在上面的上下文中總結你的答案,只要我沒有在castToColumn()函數中聲明一個數據框,那麼這個實例將不會被創建,只是一個「藍圖」 – Jake

+0

也可以,如果不是太繁重,你能分享有關此主題的合理可訪問文檔的鏈接? – Jake

+1

即使您聲明瞭一個數據幀,它也不會在內存中生成。這仍然只是一個「藍圖」。我不確定在哪裏可以找到關於此的文檔。谷歌圍繞網絡進行了一些討論,但我能在官方文檔中找到的最好的部分是關於火花RDD的一節:https://spark.apache.org/docs/latest/rdd-programming-guide.html# RDD的操作 –