共享变量背景:
广播变量
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName(s"${_01SparkBroadcastOps.getClass.getSimpleName}")
.setMaster("local[2]")
val sc = new SparkContext(conf)
val provinces = Map[String, String](
"62" -> "甘肃",
"34" -> "安徽",
"14" -> "山西",
"44" -> "湖南"
)
val cities = Map[String, (String, String)](
"05" -> ("天水", "62"),
"20" -> ("淮北", "34"),
"36" -> ("太原", "14"),
"25" -> ("韶山", "44")
)
//rdd
val stues = List(
"1 米鼎 18 1 62 05",
"2 荆波 19 0 34 20",
"3 穆书岳 23 0 14 36",
"4 程旋宇 17 1 44 25"
)
val stuRDD = sc.parallelize(stues)
//此时的关联操作,可以通过的广播变量的操作来避免shuffle的操作
val student = stuRDD.map(line => {
val fields = line.split("\\s+")
Student(fields(0), fields(1), fields(2).toInt, fields(3).toInt, fields(4), fields(5))
})
println("======================使用广播变量的方式==============================")
//创建广播变量
val pBC:Broadcast[Map[String, String]] = sc.broadcast(provinces)
val cBC:Broadcast[Map[String, (String, String)]] = sc.broadcast(cities)
student.map(stu => {
val province = pBC.value(stu.pid)//获取广播变量,并完成字段的映射-->join
val city = cBC.value(stu.cid)._1
s"${stu.id}\t${stu.name}\t${stu.gender}\t${province}\t${city}"
}).foreach(println) //map 的join
sc.stop()
}
}
case class Student(id:String, name:String, age:Int, gender:Int, pid:String, cid:String)
累加器
累加器,spark中称之为Accumulator,其作用和MR中的Counter计数器的作用相同,就是记录在计算过程中的某一些值出现的次数,比如,我们在执行wordcount或者任意计算的过程,额外地统计某个单词hello出现多少次。
此时就可以使用Accumulator累加器来完成,主要的程序不方便计算的某些值,同时可以减少一次job作业的提交,一定程度上提升了spark作业的执行效率。
注意:要想让累加器执行,必须要有action的触发,所以累加器的调用只能在一个action之后;需要注意累加器被多次调用产生的数据重复累加的问题。
object _02SparkAccumuatorOps {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
.setAppName(s"${_02SparkAccumuatorOps.getClass.getSimpleName}")
.setMaster("local[2]")
val sc = new SparkContext(conf)
val list = List(
"hello you",
"i hate you",
"i miss you",
"i love you",
"fuck you"
)
val words = sc.parallelize(list).flatMap(_.split("\\s+"))
/**
* //求多个word,you,i
* 为了完成上述操作,需要在原始操作基础之上,额外的提交一个spark作业
* 就需要额外的分配一批资源,就有可能有数据在网络中进行传输
* 效率不会特别高
* 此时就有这个一个共享变量——累加器
*/
// words.filter(word => word == "hello").count()
// val ab = Array("hello", "i", "you")
// words.filter(word => ab.contains(word)).map((_, 1)).reduceByKey(_+_)
//在计算words的过程中统计you出现了多少次
//创建累加器 选择无参版本,我们无法再sparkUI上面观察到相关的累加器的值
val acc = sc.longAccumulator("helloAcc")
val pairs = words.map(word => {
if(word == "you") {
acc.add(1)
}
(word, 1)
})
println("you出现的次数:" + acc.value + ", action执行之前")
println("pairs中总共有多少条记录:" + pairs.count())
println("you出现的次数:" + acc.value + ", action执行之后")
acc.reset()//重置累加器的值
pairs.countByKey()
/*
解决这个重复调用的问题:
1、要么在第一次出现action之后调用
2、再一次执行action之前,重置累加器的值
*/
println("you出现的次数:" + acc.value + ", action执行之后")
// Thread.sleep(1000000)
sc.stop()
}
}