spark 编程入门
接触spark也有一段时间了,记下我理解的spark,也为了和更多的开发朋友分享和交流,于是有了spark日记。它是一个通用-专用过的分布式集群运算系统,它提供了诸如sacla, java,python,r等语言的高层接口和一个经过优化的引擎去执行各种通用作业执行图。提供的工具有spark sql,spark ML, spark graphx,spark streaming用于不同的处理用途。点击查看 spark overview, 此文参考和部分翻译 spark programming-guide
安装和入门
直接下载已经编译好的文件就可以用了,这里就不介绍了,还没用过的朋友看到请移步到 这里
spark RDD
RDD (resilient distributed dataset )是spark 提供的核心概念,它是一个spark提供的数据结构,代表着一个不可修改,可分布,可容错的数据集合,该集合的元素可以分区进行并行计算。原文翻译是(a collection of elements partitioned across the nodes of the cluster that can be operated on in parallel). RDD 可以通过两种方式创建,一是由外部文件(数据源)接入来生成,例如hadoop, kafka; 另一种是由现有结合数据集合调用系统接口parallelizing 生成。
parallelizing 集合生成rdd
./bin/pyspark # 启动spark python shell data = [1, 2, 3, 4, 5] distData = sc.parallelize(data) disData.reduce(lambda x,y: x+y) # 计算总和
External Datasets生成rdd: 外部文件也分两种类型,一种是可以直接通过系统接口生成rdd的basic source: 如文件系统,Hadoop file,network file;一种是要使用专用外部依赖库提供接口来生成rdd,如kafka,Twitter,flume等。
# 通过外部文件创建 rdd distFile = sc.textFile("data.txt")
rdd operation
rdd operation分成两类,一类是transformations,把一个rdd 转成成另一种rdd; 一种是action,对该rdd进行计算并返回一个value给程序。spark对rdd的操作是 lazy 执行的,在执行transformations时并不会执行,而是到了执行action 时候才执行。另外,rdd 在执行的过程中可能遇到重新计算的过程,可以通过persist 或者 cache的方法保存在内存或横跨集群中,用于加快计算速度。
transformations,spark提供了通用的接口,详见
actions, 参考 http://spark.apache.org/docs/1.6.2/programming-guide.html#actions
spark 函数传递
用三总方式传递函数给spark执行,这里以python为例:
- 使用 匿名函数
# 继续使用上面例子
data = [1, 2, 3, 4, 5]
distData = sc.parallelize(data)
disData.reduce(lambda x,y: x+y) # 计算总和
- 使用一般函数
#
data = [1, 2, 3, 4, 5]
distData = sc.parallelize(data)
def add(x,y):
return x + y
disData.reduce(add) # 计算总和
- 使用类
data = [1, 2, 3, 4, 5]
distData = sc.parallelize(data)
class AddObject(object):
def add(self, x, y):
return x + y
def doStuff(self, rdd)
return rdd.reduce(self.add)
AddObject().doStuff(disData) # 计算总和
关于外部变量:
闭包的引用变量在local模式下运行可以被excuter正确索引到同一变量,但在cluster中,excuter复制dirver paogrem的变量值并复制到本地,所以每个excuter都有自己的复制而并不是driver的那个变量,所以计算结果会不正确。当需要更新去全局变量时候要使用 Accumulators元素输出:
输出所有元素: rdd.collect().foreach(println)
输出所有元素可能导致driver program消耗大量内存,避免此情况可以使用take; rdd.take(100).foreach(println).key-value 元素:
key-value元素在python表现为一个元祖 (1,3 );键值对数据处理通常有”shuffle”,以key为键值进行aggregate 聚合运算
For example, the following code uses the reduceByKey operation on key-value pairs to count how many times each line of text occurs in a file:
lines = sc.textFile("data.txt")
pairs = lines.map(lambda s: (s, 1))
counts = pairs.reduceByKey(lambda a, b: a + b)
spark share 变量
前面提到过,spark是一个分布式计算框架,在集群运算中需要把code,变量,数据分布到多个记得点计算。其中的变量是以复制的形式copy到节点本地存储,所以涉及到一个计算同步问题,spark share 变量有
- Broadcast variables
如你所愿,广播变量是可以让你保存一份本地read-only变量,你不能更新它。广播变量通过SparkContext.broadcast(v)来创建,同过value 属性来获取该变量值
>>> broadcastVar = sc.broadcast([1, 2, 3])
<pyspark.broadcast.Broadcast object at 0x102789f10>
>>> broadcastVar.value
[1, 2, 3]
- Accumulators
Accumulators是允许你进行”add”操作的变量,你可以自顶一个add操作使他更加灵活的实现你的逻辑。 Accumulators 使用SparkContext.accumulator(v)创建。 任务执行可以通过 add()或者 += 来执行叠加操作
>>> accum = sc.accumulator(0)
Accumulator<id=0, value=0>
>>> sc.parallelize([1, 2, 3, 4]).foreach(lambda x: accum.add(x))
scala> accum.value