join:
val rdd1 =sc.parallelize(List(("spark",1),("hadoop",1),("spark",2),("hadoop",2),("hive",2)))
sc.parallelize(List(("spark",3),("hive",3),("spark",4),("hadoop",2)))
------->d.RDD[(String, (Int, Int))
这个有点类似
val rdd0 = sc.flatMapValues(List("a"Array(1,2,3),("b",Array(4,5,6))))
----> (a,1),(a,2),(a,3)(b,4),(b,5),(b,6)
cogroup实现join的功能,
1.通过cogroup 实现局部分组聚合,好全局分组聚合从而得到(以Spark为例,list1中("spark"(1,2)),)
list2中("spark",3),完成区内聚合
2.通过flatmapValue----> ("spark",((1,2),3)) 然后遍历 t._.1iterator 和t._2.iterator 如果同时都存在组返回所以最后得出的结果为
("spark",(1,3)) ("spark",(2,3))
//join,leftJoin,rightjoin,fulljoin
//join底层默认的cogroup,cogroup用的是hashPartitioner,如果没有指定分区器,则默认为2个分区器
//
val conf = new SparkConf().setAppName("JoinDemo").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd1 = sc.parallelize(List(("spark",1), ("hadoop", 1), ("spark", 2), ("hive", 2),("flink", 2)), 2)
val rdd2 = sc.parallelize(List(("spark", 3), ("hive", 3), ("hadoop", 4)), 2)
//通过cogroup实现join类似的功能,从而了解join底层源码的工作原理
val rdd3: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2)
val rdd4: RDD[(String, (Int, Int))] = rdd3.flatMapValues(t => {
for (x <- t._1.iterator; y <- t._2.iterator) yield (x, y)
})
rdd4.saveAsTextFile("out3-join")
leftOutJoin
val conf = new SparkConf().setAppName("JoinDemo").setMaster("local[*]") val sc = new SparkContext(conf) val rdd1 = sc.parallelize(List(("spark",1), ("hadoop", 1), ("spark", 2), ("hive", 2),("flink", 2)), 2) val rdd2 = sc.parallelize(List(("spark", 3), ("hive", 3), ("hadoop", 4)), 2) val rdd: RDD[(String, (Int, Option[Int]))] = rdd1.leftOuterJoin(rdd2) //使用cogroup实现类似leftOuterJoin的功能 val rdd3: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2) //Int来自于第一个RDD的value,Option[Int]来自于第二个RDD的value,如果有就是some,如果没有就none val rdd4: RDD[(String, (Int, Option[Int]))] = rdd3.flatMapValues(t => { if (t._2.nonEmpty) { t._1.map((_, None)) } else { for (x <- t._1.iterator; y <- t._2.iterator) yield (x, Some(y)) } }) rdd4.saveAsTextFile("out-leftjoin")
rightOuterJoin
val conf = new SparkConf().setAppName("JoinDemo").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd1 = sc.parallelize(List(("spark",1), ("hadoop", 1), ("spark", 2), ("hive", 2),("flink", 2)), 2)
val rdd2 = sc.parallelize(List(("spark", 3), ("hbase", 3), ("hadoop", 4)), 2)
//val rdd: RDD[(String, (Option[Int], Int))] = rdd1.rightOuterJoin(rdd2)
//使用cogroup实现类似rightOuterJoin的功能
val rdd3: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2)
val rdd4: RDD[(String, (Option[Int], Int))] = rdd3.flatMapValues(t => {
if (t._1.isEmpty) {
t._2.map((None, _))
} else {
for (x <- t._1.iterator; y <- t._2.iterator) yield (Some(x), y)
}
})
rdd4.saveAsTextFile("out-rightjoin")
}
fullOuterJoin
val conf = new SparkConf().setAppName("FullOuterJoinDemo").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd1 = sc.parallelize(List(("spark",1), ("hadoop", 1), ("spark", 2), ("hive", 2),("flink", 2)), 2)
val rdd2 = sc.parallelize(List(("spark", 3), ("hbase", 3), ("hadoop", 4)), 2)
//val rdd: RDD[(String, (Option[Int], Option[Int])] = rdd1.fullOuterJoin(rdd2)
//使用cogroup实现类似rightOuterJoin的功能
val rdd3: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2)
val rdd4: RDD[(String, (Option[Int], Option[Int]))] = rdd3.flatMapValues{
case (i1, Seq()) => i1.iterator.map(x => (Some(x), None))
case (Seq(), i2) => i2.iterator.map(y => (None, Some(y)))
case (i1, i2) => for(a <- i1.iterator; b <- i2.iterator) yield (Some(a), Some(b))
}
rdd4.saveAsTextFile("out-fulljoin")
collect
val conf = new SparkConf().setAppName("CollectDemo").setMaster("local[*]")
val sc = new SparkContext(conf)
val rdd1 = sc.parallelize(List(1,2,3, 4,5,6), 2)
val rdd2: RDD[Int] = rdd1.map(_ * 10)
//底层执行数据操作的是在executor里,然后把执行完成的数据返回到Driver端,
//在调用runjob的时候,数据已经*10完成,
//runjob是传入rdd,计算的逻辑函数,从第0 个分区一直算到最后一个分区
val res: Array[Int] = rdd2.collect()
面试题: 如果collect的数据特别大会出现什么情况,spark只会collect一部分数据,Driver端收集多少数据根Drive内存有关系,占一个百分比,
如果超过这个内存的百分比,那么就会不再收集,
面试: 把设计好的数据是在Driver端写,还是在executor里面写,
在executor里面写,因为,在executor里面写.可以在多个Task,可以并行写,增加处理数据的效率,同时避免通过网络把数据收集到Driver端,如果收集到Driver端,必须要走网络,那么上传和处理的速度会大大减慢,
reduce; 是一个shuffle
底层传入rdd,局部聚合,全局聚合,与fold底层逻辑相似,只不过fold多了一个初始值
val rdd1 = Array((1,2,3),(4,5,6),2)
aggregate: rdd1.aggregate(100)(_+_,_+_) 最终结果为321
初始值在每个分区会使用一边,然后再全局分组聚合的时候也会执行一遍
foreach 在执行的时候是在executor里面打印的
foreachPartition() 可以将数据以分区的形式拿出来.
rdd1.foreachPartition(it=>{it.forach(println)}) ------>打印到executor里面了
//对于foreachPartition来说,底层就是传入一个函数,底层有一个函数,这个函数就是迭代器,然后把迭代器作为参数传入到你所应用到的函数中
rdd1.foreachPartition(it=>{
//建立数据库或者从连接池中取出连接
//对迭代器中的多条数据进行操作
对于foreach来说,底层就是当你传入函数时,就是一条调用一次,一条数据就返回iter,然后迭代器里面的数据,每一条都应用一下你 传入的函数,这两个都是Action,因为底层调用了sc,runJob
it.foreach(t=>{
//使用事先创建好的连接,写入到数据库(反复使用连接)
})
//关闭连接或将连接换回连接池
)}