强大算子cogroup
cogroup源码:
// 返回类型 RDD[(K, (Iterable[V], Iterable[W]))]
// 对于this或other中的每个键k,返回一个结果RDD,该RDD包含一个元组,其中包含this和other中该键的Value列表。
def cogroup[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (Iterable[V], Iterable[W]))] =
self.withScope {
if (partitioner.isInstanceOf[HashPartitioner] && keyClass.isArray) {
throw new SparkException("HashPartitioner cannot partition array keys.")
}
val cg = new CoGroupedRDD[K](Seq(self, other), partitioner)
cg.mapValues { // 对value 进行操作
case Array(vs, w1s) => //vs self的value,w1s other的value
(vs.asInstanceOf[Iterable[V]], w1s.asInstanceOf[Iterable[W]]) // 将vs和w1s 实例化为可迭代的(装到compactBuffer里面)
}
}
该算子使用的很少,但是他却功能强大,因为它作为底层算子,很多其他我们使用的比较多的算子都是该算子实现的。
intersection
// 使用cogroup 实现intersection 交集操作
val rdd1: RDD[Int] = sc.parallelize(List(1, 2, 3, 4, 5), 2)
val rdd2: RDD[Int] = sc.parallelize(List(4, 5, 6, 7, 8, 9), 2)
val cogroupedRdd: RDD[(Int, (Iterable[Null], Iterable[Null]))] = rdd1.map((_, null))
.cogroup(rdd2.map((_, null)))
cogroupedRdd.filter{
case (k,(v1,v2))=>v1.nonEmpty && v2.nonEmpty //偏函数 判断v1不为空,v2也不为空
}.map(_._1)
.foreach(println(_))
// 输出:4,5
join
// cogroup 实现 join操作
val rdd1: RDD[(String, Int)] = sc.parallelize(List(("spark", 1), ("hadoop", 1), ("spark", 2), ("hive", 2), ("flink", 2)), 2)
val rdd2: RDD[(String, Int)] = sc.parallelize(List(("spark", 3), ("hadoop", 4), ("hive", 3)), 2)
val cogroupedRdd: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2)
cogroupedRdd.flatMapValues(pair => {
for (i <- pair._1.iterator; j <- pair._2.iterator) // 求笛卡尔积
yield (i, j)
}).foreach(println(_))
输出:
(hive,(2,3))
(spark,(1,3))
(spark,(2,3))
(hadoop,(1,4))
leftOuterJoin
val rdd1: RDD[(String, Int)] = sc.parallelize(List(("spark", 1), ("hadoop", 1), ("spark", 2), ("hive", 2), ("flink", 2)), 2)
val rdd2: RDD[(String, Int)] = sc.parallelize(List(("spark", 3), ("hadoop", 4), ("hive", 3)), 2)
rdd1.leftOuterJoin(rdd2)
.foreach(println(_))
println("--------------------")
rdd1.cogroup(rdd2)
.flatMapValues(pair=>{
if (pair._2.isEmpty) { //默认rdd1 > rdd2
pair._1.iterator.map((_,None))
}else{
for (i<- pair._1.iterator; j<- pair._2.iterator)
yield (i,Some(j))
}
})
.foreach(println)
输出:
(hive,(2,Some(3)))
(spark,(1,Some(3)))
(spark,(2,Some(3)))
(hadoop,(1,Some(4)))
(flink,(2,None))
--------------------
(hive,(2,Some(3)))
(spark,(1,Some(3)))
(spark,(2,Some(3)))
(hadoop,(1,Some(4)))
(flink,(2,None))
rightOuterJoin
// cogroup 实现rightOuterJoin
val rdd1: RDD[(String, Int)] = sc.parallelize(List(("spark", 1), ("hadoop", 1), ("spark", 2), ("hive", 2), ("flink", 2)), 2)
val rdd2: RDD[(String, Int)] = sc.parallelize(List(("spark", 3), ("hadoop", 4), ("hive", 3)), 2)
println("-------rightOuterJoin-----------")
rdd2.rightOuterJoin(rdd1)
.foreach(println(_))
println("-------cogroupRdd-----------")
val cogroupRdd: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd2.cogroup(rdd1)
cogroupRdd.foreach(println(_))
println("-------resultRdd---------")
cogroupRdd.flatMapValues(pair => {
if (pair._1.isEmpty) {
pair._2.iterator.map((None, _))
} else {
for (i <- pair._1.iterator; j <- pair._2.iterator) // 当i,j有一个为null时 ,yield会跳过
yield (Some(i), j)
}
})
.foreach(println(_))
输出:
-------rightOuterJoin-----------
(hive,(Some(3),2))
(spark,(Some(3),1))
(spark,(Some(3),2))
(hadoop,(Some(4),1))
(flink,(None,2))
-------cogroupRdd-----------
(hive,(CompactBuffer(3),CompactBuffer(2)))
(flink,(CompactBuffer(),CompactBuffer(2)))
(spark,(CompactBuffer(3),CompactBuffer(1, 2)))
(hadoop,(CompactBuffer(4),CompactBuffer(1)))
-------resultRdd---------
(hive,(Some(3),2))
(spark,(Some(3),1))
(spark,(Some(3),2))
(hadoop,(Some(4),1))
(flink,(None,2))