在自定义条件下合并Spark RDD中的元素

时间:2014-12-01 06:49:02

标签: mapreduce apache-spark

如何在自定义条件下合并Spark RDD中的元素?

假设存在RDD [Seq [Int]],其中该RDD中的一些Seq [Int]包含重叠元素。任务是合并此RDD中所有重叠的Seq [Int],并将结果存储到新的RDD中。

例如,假设RDD [Seq [Int]] = [[1,2,3],[2,4,5],[1,2],[7,8,9]],结果应该[[1,2,3,4,5],[7,8,9]]。

由于RDD [Seq [Int]]非常大,我无法在驱动程序中执行此操作。是否可以使用分布式groupBy / map / reduce等来完成它?

1 个答案:

答案 0 :(得分:1)

最后我自己解决了。

这个问题可以转换为计算由RDD [Seq [Int]]中的元素形成的所有连通分量,因为合并条件(两个Seq [Int]具有重叠整数)表示两个Seq [Int]之间的连通性。

基本理念是:

  1. 为RDD [Seq [Int]]中的每个元素提供一个唯一键(.zipWithUniqueId)
  2. 通过生成的密钥在Seq [Int]中对整数进行分组,因此出现在多个Seq [Int]中的整数将具有组合在一起的相应密钥
  3. 生成RDD图,其中边是步骤2中相同组的密钥对
  4. 使用GraphX计算连接的组件,并加入结果

    val sets = Seq(Seq(1,2,3,4), Seq(4,5), Seq(1,2,3), Seq(6,7,8), Seq(9,10), Seq(7,9))
    val rddSets = sc.parallelize(sets)
                    .zipWithUniqueId
                    .map(x => (x._2, x._1)).cache()
    val edges = rddSets.flatMap(s => s._2.map(i => (i, s._1)))
                       .groupByKey.flatMap(g => {
                           var first = g._2.head
                           for (v <- g._2.drop(1)) yield {
                             val pair = (first, v)
                             first = v
                             pair
                            }
                       }).flatMap(e => Seq((e._1, e._2), (e._2, e._1)))
    
    val vertices = Graph.fromEdgeTuples[Long](edges, defaultValue = 0)
                        .connectedComponents.vertices
    rddSets.join(vertices).map(x => (x._2._2, x._2._1))
           .reduceByKey((s1, s2) => s1.union(s2).distinct)
           .collect().foreach(x => println (x._2.toString()))