Scala 如何使用RDDAPI逆转reduceByKey的结果?
我有一个RDD(键,值),我将其转换为RDD(键,列表(值1,值2,值3),如下所示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
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,我刚刚投票支持了你的答案。这种语法真是太神奇了,我甚至都不知道它的存在