一、累加器
1、背景
Spark向函数传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。Spark提供了一个共享变量–累加器,可以将工作节点的值聚合到驱动器程序中。常用于调试时对作业执行过程中的事件进行统计。
2、累加器示例
val sc = new SparkContext(...)
val input = sc.textFile(...)
val nullLines = sc.accumulator(0)
val result = input.flatMap(line => {
if(line == "") {nullLines += 1}
line.split(" ")
})
println("null lines:" + nullLines.value)
3、累加器说明
工作节点上的任务是不能访问累加器的值,从这些任务的角度来说,累加器是一个只写变量,可以在驱动器程序中调用累加器的value属性来访问累加器的值。在转化操作中,累加器通常只用于调试目的。
二、广播变量
Spark提供的另一个共享变量类型是广播变量,它可以让程序高效地向所有工作节点发送一个较大的只读值,以供一个或多个Spark操作使用。
广播变量的类型为spark.broadcast.Broadcast[]的一个对象,其中存放着类型为T的值,可以在任务中通过对Broadcast对象调用value来获取该对象的值。这个值只会被发送到各节点一次,使用的是一种高效的类型BitTorrent的通信机制。
在这个过程中,变量只会被分发到各个节点一次,应作为只读值处理,修改这个值不会影响到其他节点。满足只读要求的最简便方式是使用广播基本类型的值或者引用不可变对象,这样就无法修改广播变量的值,只能在驱动器程序的代码中修改。
Spark的Scala和Java API中默认使用的序列化库为Java序列化库,因此对于除基本类型的数组以外的任何对象都比较低效,可以使用Kryo库来加快序列化过程。
三、分区操作
基于分区对数据进行操作可以让我们避免为每个数据元素进行重复的配置工作,诸如打开数据库连接或创建随机数据生成器等操作。Spark提供基于分区的map和foreach,可以让部分代码只对RDD的每个分区运行一次,以提升效率。
当基于分区操作RDD时,Spark会为函数提供该分区中的元素的迭代器,并返回一个迭代器。基于分区的操作函数有:
(1)mapPartitions()
调用所提供的该分区中元素的迭代器,返回元素的迭代器。
(2)mapPartitionsWithIndex()
调用所提供的分区序号,以及每个分区中的元素的迭代器,返回元素的迭代器。
(3)foreachPartitions()
调用所提供的元素迭代器,无返回值。