![](/img/trans.png)
[英]How to efficiently perform this column operation on a Spark Dataframe?
[英]How to perform one operation on each executor once in spark
我有一個存儲在 S3 中的 weka 模型,其大小約為 400MB。 現在,我有一組記錄,我想在這些記錄上運行模型並執行預測。
為了執行預測,我嘗試過的是,
在驅動程序上下載並加載模型作為靜態對象,將其廣播給所有執行程序。 對預測 RDD 執行映射操作。 ----> 不工作,如在 Weka 中執行預測,模型對象需要修改並且廣播需要只讀副本。
將模型作為靜態對象下載並加載到驅動程序上,並在每個映射操作中將其發送到執行程序。 -----> 工作(效率不高,因為在每個地圖操作中,我傳遞了 400MB 對象)
在驅動程序上下載模型並將其加載到每個執行器上並將其緩存在那里。 (不知道怎么弄)
有人知道如何在每個執行器上加載模型一次並緩存它,以便我不會再次加載其他記錄嗎?
您有兩個選擇:
object WekaModel {
lazy val data = {
// initialize data here. This will only happen once per JVM process
}
}
然后,您可以在map
函數中使用惰性 val。 lazy val
確保每個工作 JVM 初始化他們自己的數據實例。 不會對data
執行序列化或廣播。
elementsRDD.map { element =>
// use WekaModel.data here
}
優勢
缺點
mapPartition
(或foreachPartition
)方法,而不僅僅是map
。這允許您初始化整個分區所需的任何內容。
elementsRDD.mapPartition { elements =>
val model = new WekaModel()
elements.map { element =>
// use model and element. there is a single instance of model per partition.
}
}
優點:
缺點
這是比惰性初始化程序對我更有效的方法。 我創建了一個初始化為空的對象級指針,並讓每個執行程序對其進行初始化。 在初始化塊中,您可以擁有一次性代碼。 請注意,每個處理批次將重置局部變量,但不會重置對象級變量。
object Thing1 {
var bigObject : BigObject = null
def main(args: Array[String]) : Unit = {
val sc = <spark/scala magic here>
sc.textFile(infile).map(line => {
if (bigObject == null) {
// this takes a minute but runs just once
bigObject = new BigObject(parameters)
}
bigObject.transform(line)
})
}
}
這種方法為每個執行器創建一個大對象,而不是其他方法的每個分區創建一個大對象。
如果將var bigObject : BigObject = null放在 main 函數命名空間中,它的行為會有所不同。 在這種情況下,它會在每個分區(即批處理)的開頭運行 bigObject 構造函數。 如果您有內存泄漏,那么這最終會殺死執行程序。 垃圾收集還需要做更多的工作。
這是我們通常做的
定義一個做這些事情的單例客戶端,以確保每個執行程序中只有一個客戶端
有一個 getorcreate 方法來創建或獲取客戶端信息,通常讓你有一個想要為多個不同模型服務的公共服務平台,然后我們可以使用像 concurrentmap 來確保線程安全和計算不存在
getorcreate 方法將在 RDD 級別內調用,如轉換或 foreachpartition,因此請確保 init 發生在執行程序級別
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.