在scala中,如何在Iterable中收集值[(元组)]

时间:2016-02-28 04:33:05

标签: scala rdd iterable

我有RDD[(Key,Iterable[(Name,Value)])]。 我正在尝试获取Name中的所有值,以便我可以获得Name的所有唯一匹配项,然后创建Index,以便创建结果RDD RDD[(Key,Iterable[(Index,Value)])]

输入示例:

(4048,CompactBuffer(("a",3.0), ("b",9.0), ("c",14.0))
(4049,CompactBuffer(("a",2.0), ("c",14.0))
(4050,CompactBuffer(("b",2.0), ("d",10.0))

输出示例:

(4048,CompactBuffer((1,3.0), (2,9.0), (3,14.0))
(4049,CompactBuffer((1,2.0), (3,12.0))
(4050,CompactBuffer((2,2.0), (4,10.0))

2 个答案:

答案 0 :(得分:3)

如果我理解你想要什么,这样的事情应该有效:

val rdd: RDD[K, Iterable[N, V]] = ???

val nameIndexMap = rdd.flatMap(_._2.map(nv => nv._1))
                      .distinct
                      .collect
                      .zipWithIndex
                      .toMap

val newRDD = rdd.mapValues(xs => xs.map(nv => (nameIndexMap(nv._1), nv._2)))

如果nameIndexMap很大或者会多次使用,那么您可能希望使用广播,例如像这样的东西

val nameIndexMapBc = sc.broadcast(nameIndexMap)  //sc is the SparkContext

val newRDD = rdd.mapValues(xs => xs.map(nv => (nameIndexMap.value)(nv._1), nv._2)))

答案 1 :(得分:1)

如果名称空间的基数高,你可以对jasonl的anwer进行一些小的补充,你可以执行类似的转换,避免将名字收集到驱动程序内存中:

val named = rdd.flatMap { case (key, values) => values.map { case (name, value) => (name, (key, value)) } }

val nameMap = named.map(_._1).distinct().zipWithUniqueId()

val indexed = named.join(nameMap).map { case (name, ((key, value), index)) => (key, (index, value)) }.groupByKey