RDD编程指引(三)(部分翻译Spark官网文章RDD Programming Guide)

本人刚开始入门学习Spark,打算先将Spark文档看一遍,顺便做点笔记,就进行一些翻译和记录。由于本人只会python,所以翻译都是以python部分代码进行。以下并非完全100%官网翻译,更多是个人理解+笔记+部分个人认为重要的内容的翻译,新手作品,请各位大神多多指正。
官网原文链接:http://spark.apache.org/docs/latest/rdd-programming-guide.html

Shared Variables

一般来说,函数总是在远程集群节点执行Spark相关操作,每个节点的函数变量都是独立的副本。这些执行节点并不会改变这些变量的值,因为在任务间读写共享变量都是较为低效的。spark提供两类特殊限定使用的共享变量:广播变量以及累加器。

Broadcast Variables

广播变量允许程序员在每台机器缓存只读变量,例如可以用来快速地给每个节点一大块输入数据集,而不需要通过任务进行拷贝。Spark会利用高效的广播算法来减少分发广播变量导致的通讯开销。

Spark处理动作由一系列阶段组成,经由shuffle操作分隔开。Spark会自动将任务所需的通用数据进行广播,这些数据被序列化后缓存并且在任务开始前进行反序列化。这就清楚表明,只有当任务在多个阶段均需要同一批数据或者当缓存反序列化数据非常重要的时候,创建广播变量才有意义。

广播变量通过调用SparkContext.broadcast(v)来创建。其实广播变量是通过对v进行装饰实现的,它的值可以通过调用值方法获得。

>>> broadcastVar = sc.broadcast([1, 2, 3])
<pyspark.broadcast.Broadcast object at 0x102789f10>

>>> broadcastVar.value
[1, 2, 3]

广播变量创建后,所有函数中值与v变量相等得值都应该替换成广播变量v,如此一来这个值就不需要多次传输到所有节点中。此外,变量v也不应该在广播后进行修改,以保证所有节点都能获取到相同的v值。

Accumulators

累加器用于在一个无序性和相关性操作中进行相加操作,实现计数和累加操作。Spark原生支持数值类型的累加器,其他类型累加器需要程序员自己实现。

用户可以创建有名字或者没有名字的累加器。如下图,web显示的是一个名叫counter的累加器的值,以及其在任务在不同阶段的值。

在web中通过追踪累加器的值来了解各个阶段进度是非常有用的(暂时不支持python环境)

可以通过SparkContext.accumulator(v)创建一个初始值为v的accmulator。任务可以通过add方法或者+=操作符对其进行累加操作。然而它们不能读取累加器的值,只有驱动节点的程序可以读取累加器的值。

下面代码展示了使用累加器累加数组中的元素

>>> accum = sc.accumulator(0)
>>> accum
Accumulator<id=0, value=0>

>>> sc.parallelize([1, 2, 3, 4]).foreach(lambda x: accum.add(x))
...
10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s

>>> accum.value
10

下面代码利用了累加器对int类型的原生支持,编写了一个自定义累加器类。AccumulatorParam类有两个方法:

(1)zero:用来提供初始值。

(2)addInPlace:用来对两个值进行相加。

下面例子是一个向量累加器。

class VectorAccumulatorParam(AccumulatorParam):
    def zero(self, initialValue):
        return Vector.zeros(initialValue.size)

    def addInPlace(self, v1, v2):
        v1 += v2
        return v1

# Then, create an Accumulator of this type:
vecAccum = sc.accumulator(Vector(...), VectorAccumulatorParam())

累加器只在处理动作中执行,Spark能够确保任务对累加器操作只执行一次(即使任务重新启动不会再次更新该值)。在转换操作中,用户应该注意任务对值的更新可能会随着任务重新执行而多次执行,从而引起累加器重复计算。

累加器并没有改变Spark的惰性计算模型。只有在RDD进行处理动作中的时候,累加器才会且只会更新一次值。但在惰性转换操作中,累加器就有可能由于没有执行计算所以没有更新(也有可能由于转换执行了多次计算可能导致累加器值进行重复计算)。以下代码片段说明了这个问题:

accum = sc.accumulator(0)
def g(x):
    accum.add(x)
    return f(x)
data.map(g)

# 由于没有处理动作触发map进行计算,accum仍然是0

Unit Testing

Spark对于流行的单元测试框架都非常友好。只需要简单创建一个SparkContext对象,master配置为‘local’,运行,并用SparkContext.stop()进行暂停和销毁。需要保证上下文环境对象在最后的块或者在测试框架的销毁方法中被清理,因为Spark不支持两个上下文环境对象同时在一个程序运行。

个人原创,欢迎转载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值