Scala 如何使用RDDAPI逆转reduceByKey的结果?

Scala 如何使用RDDAPI逆转reduceByKey的结果?,scala,apache-spark,rdd,Scala,Apache Spark,Rdd,我有一个RDD(键,值),我将其转换为RDD(键,列表(值1,值2,值3),如下所示 val rddInit = sc.parallelize(List((1, 2), (1, 3), (2, 5), (2, 7), (3, 10))) val rddReduced = rddInit..groupByKey.mapValues(_.toList) rddReduced.take(3).foreach(println) 这段代码为我提供了下一个RDD: (1,列表(2,3))(2,列表(5,7

我有一个RDD(键,值),我将其转换为RDD(键,列表(值1,值2,值3),如下所示

val rddInit = sc.parallelize(List((1, 2), (1, 3), (2, 5), (2, 7), (3, 10)))
val rddReduced = rddInit..groupByKey.mapValues(_.toList)
rddReduced.take(3).foreach(println)
这段代码为我提供了下一个RDD: (1,列表(2,3))(2,列表(5,7))(3,列表(10))

但是现在我想从我刚刚计算的rdd(rdd减少的rdd)返回rddInit

我的第一个猜测是,在关键元素和列表中的每个元素之间实现某种交叉积,如下所示:

rddReduced.map{
  case (x, y) =>
    val myList:ListBuffer[(Int, Int)] = ListBuffer()
    for(element <- y) {
      myList+=new Pair(x, element)
    }
    myList.toList
}.flatMap(x => x).take(5).foreach(println)
rddredreduced.map{
案例(x,y)=>
val myList:ListBuffer[(Int,Int)]=ListBuffer()
对于(元素x)。取(5)。foreach(println)

通过这段代码,我得到了初始RDD。但是我认为在spark作业中使用ListBuffer不是一个好的做法。有没有其他方法来解决这个问题?

根据您的问题,我认为这是您想要做的

rddReduced.map{case(x, y) => y.map((x,_))}.flatMap(_).take(5).foreach(println)

分组后会得到一个列表,可以在其中再次映射。

使用这种操作显然不是一种好的做法

根据我在spark summit课程中学到的知识,您必须尽可能多地使用
Dataframe
s和
Dataset
s,使用它们您将从spark engine的许多优化中受益

您要做的是调用
explode
,它是通过应用
sql.functions
包中的
explode
方法来实现的

解决方案如下:

 import spark.implicits._
 import org.apache.spark.sql.functions.explode
 import org.apache.spark.sql.functions.collect_list

 val dfInit = sc.parallelize(List((1, 2), (1, 3), (2, 5), (2, 7), (3, 10))).toDF("x", "y")
 val dfReduced = dfInit.groupBy("x").agg(collect_list("y") as "y")
 val dfResult = dfReduced.withColumn("y", explode($"y"))

dfResult
将包含与
dfInit

相同的数据这里有一种方法可以将分组的RDD恢复到原始状态:

val rddRestored = rddReduced.flatMap{
    case (k, v) => v.map((k, _))
  }

rddRestored.collect.foreach(println)
(1,2)
(1,3)
(2,5)
(2,7)
(3,10)

我感到惊讶的是,没有人提供Scala的理解解决方案(在编译时“去糖化”到
flatMap
map

我不经常使用这种语法,但当我使用时……我发现它非常有趣。有些人更喜欢理解而不是一系列
flatMap
map
,尤其是更复杂的转换

// that's what you ended up with after `groupByKey.mapValues`
val rddReduced: RDD[(Int, List[Int])] = ...
val r = for {
  (k, values) <- rddReduced
  v <- values
} yield (k, v)

scala> :type r
org.apache.spark.rdd.RDD[(Int, Int)]

scala> r.foreach(println)
(3,10)
(2,5)
(2,7)
(1,2)
(1,3)

// even nicer to our eyes
scala> r.toDF("key", "value").show
+---+-----+
|key|value|
+---+-----+
|  1|    2|
|  1|    3|
|  2|    5|
|  2|    7|
|  3|   10|
+---+-----+
//这就是在`groupByKey.mapValues'之后得到的结果`
val rddredreduced:RDD[(Int,List[Int])]=。。。
val r=用于{
(k,值)r.foreach(println)
(3,10)
(2,5)
(2,7)
(1,2)
(1,3)
//对我们的眼睛更好看
scala>r.toDF(“键”、“值”).show
+---+-----+
|键值|
+---+-----+
|  1|    2|
|  1|    3|
|  2|    5|
|  2|    7|
|  3|   10|
+---+-----+

毕竟,这就是为什么我们喜欢Scala的灵活性,不是吗?

map
后跟
flatMap(identity)
=>
flatMap
。使用
element.map(成对(…)
-使用
ListBuffer
使代码过于复杂。将
结对
作为一个案例类。非常感谢@Jacked,我刚刚投票支持了你的答案。这种语法真是太神奇了,我甚至都不知道它的存在