Spark 官方文档快速入门指南
Spark架构 -Spark教程
RDD(resilient distributed dataset)弹性分布式数据集,对分布式数据和计算的基本抽象。
每个 Spark 应用 由一个 驱动器程序(driver program)发起集群上的并行操作,驱动器程序一般要管理多个 执行器(executor)节点。
当我们在集群上执行一个操作,不同的节点会对文件不同部分展开计算。
驱动器程序 发起集群上的并行操作,定义了集群上的分布式数据集,进行相关操作。包含了一个 main 函数。
驱动器程序通过一个 SparkContext 对象访问 Spark。这个对象代表对计算集群的一个连接。
我们可以用 SparkContext 创建RDD。
Spark 会自动动将函数发送到各个执行器器节点上,我们可以在单一的驱动器程序中编辑,并让代码自动运行在多个节点上。
Spark 执行 Python 需要将应用写成 Python 脚本,使用 bin/spark-submit 脚本提交运行。
Spark 对数据的操作大致可以分为 1. 创建 RDD 2. 转化已有 RDD 3. 调用 RDD 操作
转化是由一个 RDD 生成一个新的 RDD ,转化是对 RDD 进行一个操作返回结果到驱动器程序或外部存储系统。
bin/spark-submit my_script.py
一般 Spark 程序按照如下方式工作:
(1)从外部数据创建 RDD
(2)对 RDD 进行转化,定义的新的 RDD
(3)告诉 RDD 需要被重用的中间结果执行 persist () 操作
(4)触发计算
导入 Spark 包,先创建一个 SparkConf 对象配置应用,然后基于 SparkConf 创建一个 SparkContext 对象。
from pyspark import SparkConf, SparkContext
conf = SparkConf().setMaster("local").setAppName("My App")
# setMaster 集群URL:告诉Spark如何连接到集群。local 单机单线程
# setAppName 应用名,连接到集群时候在集群管理器用户界面找应用
sc = SparkContext(conf = conf)
关闭方法: stop() / System.exit(0) / sys.exit()
RDD(resilient distributed dataset)弹性分布式数据集,一个不可变的分布式对象集合。
可以分为:(1)读取外部数据集。(2)在驱动器城区里分发对象合集。
将一个已有的集合传给 SparkContext。例如:
lines = sc.paralleize(["pandas", "i like pandas"])
lines = sc.textFile("/path/to/README.md")
用户可以在任何时候定义新的 RDD 但是 Spark 只会惰性计算,当我们调用转化操作时,不会立即执行。默认情况下 Spark 的 RDD 会在每次对他们进行行动操作时重新计算,如果需要在多个行动中重用一个 RDD 可以用 RDD.persist() 让 Spark 缓存 RDD 到内存,反复查询和分析。
Spark 对 转化和操作的执行方式不同,需要明确使用的操作的类型。
返回值判断:转化操作返回 RDD ,行动操作返回其他数据类型。
转化操作不会改变已有的 RDD 数据,而是返回一个全新的 RDD。后续仍可使用原始 RDD。
另外 Spark 会用谱系图记录 RDD 之间的依赖关系。
行动操作会生成计算结果,强制执行求值必须用到的 RDD 的转化操作。
(1)传递比较短的函数,lamabda 表达式
word = rdd.filter(lambda s: "error" in s)
def containsError(s):
return "error" in s
word = filter(containsError)
注意传递函数会把函数所在的对象也序列化传出去,把整个对象发送到工作节点。应该把需要的字段从对象中取出来作为局部变量,传递局部变量。
class WordFunctions(object):
...
def getMatchesNoReference(self, rdd):
query = delf.query
return rdd.filter(lambda x:query in x)
map() 解析字符串,返回 Double 值。
类似 map() 对每个元素应用,但返回是 一个返回值序列的迭代器。输出的 RDD 不是由迭代器组成,而是一个包含各个迭代器可访问的所有元素的 RDD。常用于将一个输入字符串切分为单词。返回的是一个由各列表中的元素组成的 RDD, 而不是一个由列表组成的RDD。
lines = sc.parallelize(["hello world", "hi"])
words = lines.flatMap(lambda line: line.split(" "))
words.first() // 返回"hello"
(返回:{"hello", "word", "hi"},而不是 { ["hello", "world"], ["hi"] } 。)
函数
必须是Iterator => Iterator
类型。mapPartitions
,为函数提供了一个表示分区索引的整数值,因此当在类型T的RDD上运行时,func
必须是类型(Int,Iterator )=> Iterator
。注意,开销很大,需要将所有数据通过网络进行数据混洗。
(K,V)
对的数据集上调用时,它返回(K,Iterable)
对的数据集。(K,V)
对的数据集时,返回(K,V)
对的数据集,其中使用给定的reduce
函数func
聚合每个键的值,该函数必须是类型(V,V)=>V
。(K,V)
对的数据集时,返回(K,U)
对的数据集,其中使用给定的组合函数和中性“零”值聚合每个键的值。ascending
参数中所指定。(K,V)
和(K,W)
的数据集时,返回(K,(V,W))
对的数据集以及每个键的所有元素对。通过leftOuterJoin
,rightOuterJoin
和fullOuterJoin
支持外连接。(K,V)
和(K,W)
的数据集时,返回(K,(Iterable,Iterable))
元组的数据集。此操作也称为groupWith
。numPartitions
。sum = rdd.reduce(lambda x, y: x + y)
sumCount = nums.aggregate((0.0),
(lambda acc, value: (acc[0] + value, acc[1] + 1),
(lambda acc1, acc2: (acc1[0] + acc2[0], acc1[1] + acc2[1]))))
return sumCount[0] / float(sumCount[1])
take(1)
)。SparkContext.objectFile()
加载。为了避免多次计算同一个 RDD ,可以让Spark对数据进行持久化存储一个RDD。Spark的缓存是容错的。在任何情况下,如果RDD的分区丢失,它将使用最初创建它的转换自动重新计算。
我们可以为 RDD 选择不同的持久化级别。
_2 把持久化的数据分成两份存储。
unpersist( ) 手动把持久化的RDD从缓存中移除。