RDD
具体请查看
https://blog.csdn.net/weixin_43497444/article/details/105349406
累加器(共享只写)
累加器用来对信息进行聚合,通常在向 Spark传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。如果我们想实现所有分片处理时更新共享变量的功能,那么累加器可以实现我们想要的效果。
注意:
(1)工作节点上的任务不能访问累加器的值。从这些任务的角度来看,累加器是一个只写变量。
(2)对于要在行动操作中使用的累加器,Spark只会把每个任务对各累加器的修改应用一次。因此,如果想要一个无论在失败还是重复计算时都绝对可靠的累加器,我们必须把它放在 foreach() 这样的行动操作中。转化操作中累加器可能会发生不止一次更新。
自定义累加器
实现自定义类型累加器需要继承AccumulatorV2并覆写要求的方法。代码如下
package accumlator
import org.apache.spark.util.AccumulatorV2
class MyAccu extends AccumulatorV2[Int, Int] {
var sum = 0
//判断是否为空
override def isZero: Boolean = sum == 0
//复制
override def copy(): AccumulatorV2[Int, Int] = {
val accu = new MyAccu
accu.sum = this.sum
accu
}
//重置
override def reset(): Unit = sum = 0
//累加
override def add(v: Int): Unit = sum += v
//合并
override def merge(other: AccumulatorV2[Int, Int]): Unit = sum += other.value
//返回值
override def value: Int = sum
}
调用自定义累加器
import org.apache.spark.rdd.RDD
import org.apache.spark.{Accumulator, SparkConf, SparkContext}
object AccuTest {
def main(args: Array[String]): Unit = {
//创建SparkConf
val sparkConf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("AccuTest")
//创建SC
val sc = new SparkContext(sparkConf)
//创建自定义累加器对象
val accu = new MyAccu
//注册累加器
sc.register(accu)
//创建RDD
val value: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4))
//在行动算子中对累加器的值进行修改
value.foreach { x =>
accu.add(1)
println(x)
}
//打印累加器的值
println(accu.value)
//关闭SparkContext
sc.stop()
}
}
广播变量(共享只读)
广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个或多个Spark操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表,甚至是机器学习算法中的一个很大的特征向量,广播变量用起来都很顺手。 在多个并行操作中使用同一个变量,但是 Spark会为每个任务分别发送。
scala> val broadcastVar = sc.broadcast(Array(1, 2, 3))
broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]] = Broadcast(35)
scala> broadcastVar.value
res33: Array[Int] = Array(1, 2, 3)
使用广播变量的过程如下:
(1) 通过对一个类型T的对象调用SparkContext.broadcast创建出一个Broadcast[T]对象。任何可序列化的类型都可以这么实现。
(2) 通过value属性访问该对象的值(在Java中为value()方法)。
(3) 变量只会被发到各个节点一次,应作为只读值处理(修改这个值不会影响到别的节点)。