如何将RDD [(Key,Value)]转换为Map [Key,RDD [Value]]

时间:2015-01-23 13:54:36

标签: scala bigdata apache-spark rdd

我搜索了很长时间的解决方案,但没有得到任何正确的算法。

在scala中使用Spark RDD,我怎么能将RDD[(Key, Value)]转换为Map[key, RDD[Value]],因为我知道我不能使用可能会将数据加载到内存中的collect或其他方法?

事实上,我的最终目标是按键循环Map[Key, RDD[Value]]并为每个saveAsNewAPIHadoopFile致电RDD[Value]

例如,如果我得到:

RDD[("A", 1), ("A", 2), ("A", 3), ("B", 4), ("B", 5), ("C", 6)]

我想:

Map[("A" -> RDD[1, 2, 3]), ("B" -> RDD[4, 5]), ("C" -> RDD[6])]

我想知道在filter的每个密钥A,B,C上使用RDD[(Key, Value)]进行此操作是否花费不会太多,但我不知道是否多次调用过滤器有不同的键会有效吗? (当然不是,但可能使用cache?)

谢谢

3 个答案:

答案 0 :(得分:2)

你应该使用像这样的代码(Python):

rdd = sc.parallelize( [("A", 1), ("A", 2), ("A", 3), ("B", 4), ("B", 5), ("C", 6)] ).cache()
keys = rdd.keys().distinct().collect()
for key in keys:
    out = rdd.filter(lambda x: x[0] == key).map(lambda (x,y): y)
    out.saveAsNewAPIHadoopFile (...)

一个RDD不能成为另一个RDD的一部分,您无法只收集密钥并将其相关值转换为单独的RDD。在我的示例中,您将遍历缓存的RDD,这是正常的,并且可以快速工作

答案 1 :(得分:0)

听起来你真正想要的是将KV RDD保存到每个键的单独文件中。而不是创建Map[Key, RDD[Value]]考虑使用MultipleTextOutputFormat similar to the example here.代码就是示例中的所有内容。

这种方法的好处是,您可以保证在随机播放后仅通过RDD一次,并获得您想要的相同结果。如果您通过过滤并按照另一个答案中的建议创建多个ID(除非您的源支持下推过滤器),您最终会为每个单独的键对数据集进行一次传递,这会更慢。

答案 2 :(得分:-1)

这是我的简单测试代码。

val test_RDD = sc.parallelize(List(("A",1),("A",2), ("A",3),("B",4),("B",5),("C",6)))
val groupby_RDD = test_RDD.groupByKey()
val result_RDD = groupby_RDD.map{v => 
    var result_list:List[Int] = Nil
    for (i <- v._2) {
        result_list ::= i
    }
    (v._1, result_list)
}

结果如下

result_RDD.take(3)
>> res86: Array[(String, List[Int])] = Array((A,List(1, 3, 2)), (B,List(5, 4)), (C,List(6)))

或者你可以这样做

val test_RDD = sc.parallelize(List(("A",1),("A",2), ("A",3),("B",4),("B",5),("C",6)))
val nil_list:List[Int] = Nil
val result2 = test_RDD.aggregateByKey(nil_list)(
    (acc, value) => value :: acc,
    (acc1, acc2) => acc1 ::: acc2 )

结果就是这个

result2.take(3)
>> res209: Array[(String, List[Int])] = Array((A,List(3, 2, 1)), (B,List(5, 4)), (C,List(6)))