如何在Spark中将RDD拆分成多个?

时间:2016-03-15 22:09:53

标签: java apache-spark

如果我对groupByKey执行基本的JavaRdd<Tuple2<String, String>>操作,我会得到JavaPairRdd<Tuple2<String, Iterable<String>>>

someStartRdd.groupByKey()

因为每个元组中的迭代的大小将相当大(数百万)并且键的数量也将变得很大,我想以流式并行方式处理每个迭代,如同RDD。理想情况下,我喜欢每个键的RDD。

目前我唯一能想到的是收集,创建列表然后parallelize

List<Tuple2<String, Iterable<String>>> r1 = someStartRdd.groupByKey().collect();
for (Tuple2<String, Iterable<String>> tuple : r1){
    List<String> listForKey = MagicLibrary.iterableToString(tuple._2());
    JavaRdd<String> listRDD = sparkContext.parallelize(listForKey);
    ...start job on listRDD...
}

但我不想把所有东西都放在内存中来创建列表。更好的解决方案?

2 个答案:

答案 0 :(得分:2)

如果你有大量的钥匙和每个钥匙的大量价值,你几乎没有运气。 Spark在长而窄的数据上工作得最好,将RDD分成多个RDD的唯一可靠方法是应用迭代过滤。你会在这里找到解释原因:How to split a RDD into two or more RDDs?

Scala Spark: Split collection into several RDD?中描述的另一种方法是明确地对数据进行分组,但由于它需要非惰性评估,因此不太可能使用大量密钥。

最后,由于2GB限制,数据偏差和大型shuffle的总体成本,重新分区可能不起作用。

记住所有这些可能的策略是尝试以一种利用方式构建算法,而不必明确地移动数据,除非有必要。您可以使用多种方法,包括采样,盐析和不同的近似值。

答案 1 :(得分:0)

你可以尝试以下解决方案,虽然我会建议不要使用它,因为它意味着很多shuffle操作,但是会实现你以流式并行方式处理每个键&#34; 迭代的目标,就像RDD一样。理想情况下,我喜欢每个密钥的RDD。&#34;

 List<String> keys = someStartRdd.keys().distinct().collect();
 HashMap<String,Integer> keysHash = new HashMap<String,Integer>();
 int pos = 0;
 for (String key : keys){
     keysHash.put(key,pos++);
 }
 repartitionedRDD = 
            someStartRdd.repartitionAndSortWithinPartitions(    
                  new CustomPartitioner(keysHash),//Partition your RDD
                  new CustomComparator()) //Sort by key the output

CustomPartinioer作为

     public static class CustomPartitioner extends Partitioner implements Serializable
{
    private static final long serialVersionUID = 1L;
    private HashMap<String,Integer> keysHash;
    public CustomPartitioner(HashMap<String,Integer> keysHash){
        this.keysHash = keysHash 
    }

    @Override
    public int getPartition(Object key) {
        return ((int) hashKeys.get((String) key);
    }

    @Override
    public int numPartitions() {
        return hashKeys.size();
    }       
} 

之后,您可以流式并行方式处理&#34; &#34;像这样

repartitionedRDD.groupByKey().mapPartitions(new FlatMapFunction ...)