[英]Spark flatMap/reduce: How to scale and avoid OutOfMemory?
我正在將一些map-reduce代碼遷移到Spark中,並且在構造Iterable返回函數時遇到問題。 在MR代碼中,我有一個由鍵分組的reduce函數,然后(使用multipleOutputs)對值進行迭代,並使用寫入(在多個輸出中,但這並不重要)這樣的代碼(簡化):
reduce(Key key, Iterable<Text> values) {
// ... some code
for (Text xml: values) {
multipleOutputs.write(key, val, directory);
}
}
但是,在Spark中,我翻譯了地圖,並將其簡化為以下序列:mapToPair-> groupByKey-> flatMap,在某些書中建議...。
mapToPair基本上是通過functionMap添加一個Key,該鍵基於記錄上的某些值為該記錄創建一個Key。 有時,密鑰可能具有很高的基數。
JavaPairRDD<Key, String> rddPaired = inputRDD.mapToPair(new PairFunction<String, Key, String>() {
public Tuple2<Key, String> call(String value) {
//...
return functionMap.call(value);
}
});
向rddPaired應用了RDD.groupByKey()以獲取RDD來提供flatMap函數:
JavaPairRDD<Key, Iterable<String>> rddGrouped = rddPaired.groupByKey();
分組后,flatMap調用執行reduce 。 在這里, 操作是一個轉換:
public Iterable<String> call (Tuple2<Key, Iterable<String>> keyValue) {
// some code...
List<String> out = new ArrayList<String>();
if (someConditionOnKey) {
// do a logic
Grouper grouper = new Grouper();
for (String xml : keyValue._2()) {
// group in a separate class
grouper.add(xml);
}
// operation is now performed on the whole group
out.add(operation(grouper));
} else {
for (String xml : keyValue._2()) {
out.add(operation(xml));
}
return out;
}
}
它的工作原理很好……使用沒有太多記錄的鍵。 實際上,當具有大量值的鍵在化簡中輸入“ else”時,它將被OutOfMemory中斷。
注意:我已經包括了“ if”部分來解釋我要產生的邏輯,但是失敗是在輸入“ else”時發生的……因為當數據輸入“ else”時,通常意味着會有更多的值由於數據的性質。
顯然,必須將所有分組值保留在“外”列表中,如果鍵具有數百萬條記錄,它將無法擴展,因為它將把它們保留在內存中。 我已經到了發生OOM的地步(是的,這是在執行上面的“操作”時需要內存的操作-沒有給出任何操作。盡管這不是很昂貴的內存操作)。
有什么辦法可以避免這種情況以擴展規模? 通過使用其他一些指令復制行為以更可擴展的方式達到相同的輸出,或者能夠派出Spark值進行合並(就像我以前對MR所做的那樣)...
在flatMap
操作中進行條件處理效率很低。 您應該檢查外部條件以創建2個不同的RDD並分別處理它們。
rddPaired.cache();
// groupFilterFunc will filter which items need grouping
JavaPairRDD<Key, Iterable<String>> rddGrouped = rddPaired.filter(groupFilterFunc).groupByKey();
// processGroupedValuesFunction should call `operation` on group of all values with the same key and return the result
rddGrouped.mapValues(processGroupedValuesFunction);
// nogroupFilterFunc will filter which items don't need grouping
JavaPairRDD<Key, Iterable<String>> rddNoGrouped = rddPaired.filter(nogroupFilterFunc);
// processNoGroupedValuesFunction2 should call `operation` on a single value and return the result
rddNoGrouped.mapValues(processNoGroupedValuesFunction2);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.