繁体   English   中英

Spark flatMap / reduce:如何缩放和避免OutOfMemory?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM