package com.lyzx.day34
import org.apache.spark._
class T2 {
/**
* join方法深入理解
* join类似于sql中的inner join会把键完全匹配的项列以(key,(v1,v2))的形式列出来
* leftOuterJoin 类似于SQL中的left outer join 把左表的全部列出来,右表中不匹配的用None表示
* (3,(3,Some(3))),(4,(4,Some(4))),(1,(1,None))
*
* @param sc
*/
def f1(sc:SparkContext): Unit ={
val rdd1 = sc.parallelize(Array(1,2,3,4,5))
val rdd2 = sc.parallelize(Array(4,5,6,7))
val pairRdd1 = rdd1.map(x=>(x,x))
val pairRdd2 = rdd2.map(x=>(x,x))
// pairRdd1.join(pairRdd2)
// .foreach(println)
pairRdd1.leftOuterJoin(pairRdd2)
.foreach(println)
}
/**
* 对于join之前进行co-partition和不进行co-partition的效率测试
* 实测join之前进行co-partition操作的效率高于直接join
* 注意:数据量小的时候情况不一定
* @param sc
*/
def f2(sc:SparkContext): Unit ={
//产生两个RDD
val rdd1 = sc.parallelize(1 to 18,3)
val rdd2 = sc.parallelize(13 to 30,3)
//映射RDD
val pairRdd1 = rdd1.map(x=>(x,x))
val pairRdd2 = rdd2.map(x=>(x,x))
//查看每个分区里的数据,调试时使用
// pairRdd1.mapPartitionsWithIndex((index,itr)=>{
// println("index1="+index)
// while(itr.hasNext){
// print("-"+itr.next())
// }
// println()
// for(v <- itr) yield v
// }).collect()
//
// pairRdd2.mapPartitionsWithIndex((index,itr)=>{
// println("index2="+index)
// while(itr.hasNext){
// print("="+itr.next())
// }
// for(v <- itr) yield v
// }).collect()
val start1 = System.currentTimeMillis()
//直接做join并记录时间
println("start1="+start1)
val joinRDD = pairRdd1.join(pairRdd2)
.mapPartitionsWithIndex((index,itr)=>{
println("pairRDD1,Index:"+index)
while(itr.hasNext){
print("-"+itr.next())
}
for(v <- itr) yield v
})
// .foreach(x=>print())
println("joinRDD.partitions.length:"+joinRDD.partitions.length)
val end1 = System.currentTimeMillis()
println("耗时="+(end1-start1)) //2563
val start2 = System.currentTimeMillis()
val group1 = pairRdd1.groupByKey()
val group2 = pairRdd2.groupByKey()
// println("#############################")
// 查看数据,调试使用
group1.mapPartitionsWithIndex((index,itr)=>{
println("group1-index1="+index)
while(itr.hasNext){
print("-"+itr.next())
}
println()
for(v <- itr) yield v
}).collect()
group2.mapPartitionsWithIndex((index,itr)=>{
println("group2-index1="+index)
while(itr.hasNext){
print("="+itr.next())
}
println()
for(v <- itr) yield v
}).collect()
println("start2="+start2)
group1.join(group2)
.mapPartitionsWithIndex((index,itr)=>{
println("pairRDD2,Index:"+index)
while(itr.hasNext){
print("="+itr.next())
}
for(v <- itr) yield v
}).foreach(x=>print())
val end2 = System.currentTimeMillis()
println("耗时:"+(end2-start2)) //2000
}
/**
* partitionBy的使用
* @param sc
*/
def f3(sc:SparkContext): Unit ={
val rdd1 = sc.parallelize(1 to 40,4).map(x=>(x,x))
rdd1
.mapPartitionsWithIndex((index,itr)=>{
print("index:"+index)
while(itr.hasNext){
print(" "+itr.next())
}
println()
for(v <- itr) yield v
})
.foreach(x=>print("-"+x))
println("###################################")
rdd1.partitionBy(new org.apache.spark.HashPartitioner(rdd1.partitions.length))
.mapPartitionsWithIndex((index,itr)=>{
print("index:"+index)
while(itr.hasNext){
print(" "+itr.next())
}
println()
for(v <- itr) yield v
})
.foreach(x=>print("-"+x))
}
/**
* 关于Spark的并行度的问题
* 修改并行度的方式
* 方法1:直接在代码中以local[*]的形式
* 方法2:conf.set("spark.default.parallelism","4")
* 方法3:val rdd = sc.parallelize(10 to 200,numPartitions)
* 优先级: 方法3>方法2>方法1
* @param sc
*/
def f4(sc:SparkContext): Unit ={
val rdd = sc.parallelize(10 to 200)
println(rdd.partitions.length)
}
/**
* 关于filter后数据倾斜的问题
* 如果在使用filter算子后发现数据倾斜问题
* 那么可以通过将RDD[K]=>RDD[K,V]形式的RDD在使用默认的 HashPartitioner进行分区后
* 在使用map算子转换回来
*
* 如果RDD[T] 其中T是自定义对象可以使用自定义分区器进行分区
* 注意:网上有人说使用filter+coalesce算子可以解决问题
* 经过我实际测试发现并不能完全解决数据倾斜问题
*
* @param sc
*/
def f5(sc:SparkContext): Unit ={
val rdd = sc.parallelize(1 to 30,5).cache()
rdd.mapPartitionsWithIndex((index,itr)=>{
println("index1:"+index+" ")
while(itr.hasNext){
val line = itr.next()
print("<|"+index+">"+line)
}
println()
for(v <- itr) yield v
})
rdd
.filter(_>10)
.map(x=>(x,1))
.partitionBy(new HashPartitioner(3))
.map(x=>x._1)
.mapPartitionsWithIndex((index,itr)=>{
println("index2:"+index+" ")
while(itr.hasNext){
val line = itr.next()
print("<||"+index+">"+line)
}
println()
for(v <- itr) yield v
})
.collect()
}
/**
* 使用自定义的分区器对数据进行分区
* @param sc
*/
def f6(sc:SparkContext): Unit ={
val r1 = "lyzx,10,1"
val r2 = "lyzx,11,2"
val r3 = "lyzx,12,3"
val r4 = "lyzx,13,4"
val r5 = "lyzx,14,5"
val r6 = "lyzx,15,6"
val r7 = "lyzx,16,7"
val r8 = "lyzx,17,8"
val r9 = "lyzx,18,9"
val r10 = "lyzx,19,10"
val r11 = "lyzx,20,11"
val arr = Array(r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11)
val rdd = sc.parallelize(arr,5)
val pRdd= rdd.map(x=>x.split(","))
.map(x=>new Person(x(0),x(1).toInt,x(2).toInt))
// pRdd.mapPartitionsWithIndex((index,itr)=>{
// while(itr.hasNext){
// println("["+index+"] "+itr.next())
// }
// for(v <- itr) yield v
// }).collect()
pRdd
.filter(x=>x.age > 15)
.map(x=>(x,1))
.partitionBy(new No_1_Partitioner(3))
.map(x=>x._1)
.mapPartitionsWithIndex((index,itr)=>{
while(itr.hasNext){
println("<"+index+"> "+itr.next())
}
for(v <- itr) yield v
})
.collect()
}
}
object T2{
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("day34").setMaster("local")
conf.set("spark.default.parallelism","4")
val sc = new SparkContext(conf)
val t = new T2
// t.f1(sc)
// t.f2(sc)
// t.f3(sc)
// t.f4(sc)
// t.f5(sc)
t.f6(sc)
sc.stop()
}
}
case class Person(name:String,var age:Int,id:Int){
override def toString: String = {
"[name="+name+",age="+age+",id="+id+"]"
}
}
class No_1_Partitioner(num:Int) extends Partitioner{
override def numPartitions: Int = num
println("....No_1_Partitioner["+num+"]被创建......")
//按照年龄%num来分区,当然在实际使用中还是以业务为准
override def getPartition(key: Any): Int = {
val p = key.asInstanceOf[Person]
val pr = p.age % num
print("========"+p.age+"%"+num+"="+pr)
pr
}
}
《深入理解Spark》之join和数据倾斜问题
最新推荐文章于 2025-05-06 10:49:06 发布