在Scala中使用RDD.map()执行嵌套for循环

时间:2017-10-12 11:36:28

标签: scala apache-spark rdd

我是Spark和Scala的新手,并且拥有Java背景。我已经在haskell中完成了一些编程,所以对于函数式编程来说并不是全新的。

我正在尝试完成某种形式的嵌套for循环。我有一个RDD,我想根据RDD中的每两个元素进行操作。伪代码(类似java)看起来像这样:

// some RDD named rdd is available before this
List list = new ArrayList();
for(int i = 0; i < rdd.length; i++){
   list.add(rdd.get(i)._1);
   for(int j = 0; j < rdd.length; j++){
      if(rdd.get(i)._1 == rdd.get(j)._1){
         list.add(rdd.get(j)._1);
      }
   }
}
// Then now let ._1 of the rdd be this list

我的scala解决方案(不起作用)如下所示:

  val aggregatedTransactions = joinedTransactions.map( f => {
     var list = List[Any](f._2._1)
     val filtered = joinedTransactions.filter(t => f._1 == t._1)

     for(i <- filtered){
       list ::= i._2._1
     }

     (f._1, list, f._2._2)
  })

如果两个项目的._1相等,我正试图将项目_2._1放入列表中。 我知道我不能在另一个map函数中做任何过滤器或map函数。我已经读过你可以用连接来实现这样的东西,但我不知道如何将这些项目实际放入列表或任何可用作列表的结构中。

如何使用RDD实现这样的效果?

1 个答案:

答案 0 :(得分:0)

假设您的输入的格式RDD[(A, (A, B))]适用于某些类型A, B,并且预期结果的格式应为RDD[A] - 而不是列表(因为我们希望保持数据的分布) - 这似乎可以满足您的需求:

rdd.join(rdd.values).keys

<强>详情:

很难理解确切的输入和预期输出,因为两者的数据结构(类型)都没有明确说明,并且代码示例没有很好地解释该要求。所以我会做一些假设,并希望它能对你的具体情况有所帮助。

完整的例子,我假设:

  • 输入RDD的类型为RDD[(Int, (Int, Int))]
  • 预期输出的格式为RDD[Int],并且包含大量重复项 - 如果原始RDD多次使用“键”X,则每次匹配(._2._1)中每次匹配都会出现一次X作为关键

如果我们试图解决这个问题 - 这个join会解决它:

// Some sample data, assuming all ints
val rdd = sc.parallelize(Seq(
  (1, (1, 5)),
  (1, (2, 5)),
  (2, (1, 5)),
  (3, (4, 5))
))

// joining the original RDD with an RDD of the "values" -
// so the joined RDD will have "._2._1" as key
// then we get the keys only, because they equal the values anyway
val result: RDD[Int] = rdd.join(rdd.values).keys

// result is a key-value RDD with the original keys as keys, and a list of matching _2._1
println(result.collect.toList) // List(1, 1, 1, 1, 2)