1、spark2.0 工作依靠python2.6+或python3.4+ ,他可以使用标准的cpython解释器,所以说C libraries 例如numpy可以使用,它工作依靠pypy2.3+
bin/spark-submit
bin/pyspark
去运行一个交互式的python shell。
若果你想获得HDFS的数据,你需要建立spark与你的hdfs对应版本的联系,
最后,你需要import一些spark的包到你的程序中,例如:
from pyspark import SparkContext , SparkConf
PySpark 需要 driver 和 workers 有相同的python版本,你可以利用PYSPARK_PYTHON 设置你喜欢的python版本。
2、初始化Spark
Spark程序第一个必须要做的是:创建一个SparkContexr对象,他会告诉Spark如何访问集群。在建立一个SparkContext对象之前你需要建立一个SparkConf对象,sparkConf对象包括了你的应用的信息。
conf = SparkConf().setAppName(appName).setMaster(master)
sc = SparkContext(conf=conf)
master =====> spark、mesos、yarn、或者local 运行在本地模型
在实际中,当运行程序在集群上时,不会设置master ,但当在本地测试或者单元测试时,你可以运用local
3、利用shell
4、弹性分布式数据集 RDDs
4.1并行集合(parallelize colleactions)
在程序中,并行的集合有SparkCinext的parallelize方法来实现,通过一个现存的集合或者可迭代数据,集合中的元素被复制去构建一个可以并行执行的分布式的数据集。eg:
data = [1, 2, 3, 4, 5]
distData = sc.parallelize(data)
一旦被创建,这个分布式的数据集就可以并行执行。eg:我们可以利用distData.reduce(lambda a, b: a + b) 对list中的元素累加求和。通常情况下,你希望你的集群上的cpu有2-4个划分。通常情况下,spark会基于你的集群自动设定划分的数量。然而你也可以自己设定(e.g. sc.parallelize(data, 10)
).,通过parallelize的第二个参数。
4.2外部数据集
Cassandra, HBase, Amazon S3 等,Spark 支持 text files, SequenceFiles,和 any other Hadoop InputFormat.
text file 的RDDs创建通过SparkContext的textFile的方法,这个方法利用文件的URI,以行的方式读取为一个集合,eg:
>>> distFile = sc.textFile("data.txt")
(1)、如果利用本地文件系统的一个路径,这个文件必须在worker节点上可以以同样的路径访问。不论是拷贝文件到多有的files或者是利用共享文件系统。
(2)、所有的Spark文件输入方法,包括textfile,支持目录,压缩文件或者通配符。rg:
textFile("/my/directory")
,
textFile("/my/directory/*.txt")
, and
textFile("/my/directory/*.gz")
.
(3)、textfile方法有一个可选的第二参数设置文件的分区数量。
除了textflie方法,pyspark还支持其他几种data formats:
SparkContext.wholeTextFiles:可以读取一个目录下的多个文件
RDD.saveAsPickleFile
and
SparkContext.pickleFile:支持保存一个RDD 序列化为一个python对象
SequenceFile and Hadoop Input/Output Formats
注意:这些方式目前还是实验性的,将来或许会被SparkSQL所代替,因为SparkSQL是首选方法。
4.3 保存和加载SequenceFiles
Writables 是不需要的。
>>> rdd = sc.parallelize(range(1, 4)).map(lambda x: (x, "a" * x ))
>>> rdd.saveAsSequenceFile("path/to/file")
>>> sorted(sc.sequenceFile("path/to/file").collect())
[(1, u'a'), (2, u'aa'), (3, u'aaa')]
4.4
保存和加载其他Hadoop输入/输出格式:
针对新的或老的hadoop MR API,pySpark 可以读取任何hadoop输入格式或者写任何hadoop输出格式,
5、RDD操作
5.1 RDDs支持两种不同类型的操作
transformations:通过已经存在的数据集创建一个新的数据集
actions:在数据集上执行完一个计算后,返回驱动程序一个值。
eg:
map:一个transformation 对数据集的每个元素执行一个函数,返回一个新的数据集
reduce:一个action,汇集RDD的所有元素利用一个函数,返回一个结果给驱动程序
reduceByKey : 返回一个分布式的数据集
在Spark中所有的tansformation都是lazy的,并不是立刻计算它们的结果,而是记住这些转换。当一个action需要返回驱动程序一个结果时候,这些transfomaton才会执行。
默认情况下,对于每一个transformation,在其上运行一个action,可以使其执行。然而可以利用persist(或cache)方法,将元素防到集群上,当下一次请求时,可以快速的获得他。
5.2 Spark 中的传递函数
Spark的驱动程序在机上上运行时非常依赖与传递函数,有三种推荐方式去运行它:
(1)、lambda表达式
(2)、局部def 函数
(3)、顶级功能模块
5.3理解闭包
Spark的一个难点是:在集群上执行代码时,理解变量和函数的范围和作用域。在变量的作用范围之外修改变量时混乱的源泉。
counter = 0
rdd = sc.parallelize(data)
# Wrong: Don't do this!!
def increment_counter(x):
global counter
counter += x
rdd.foreach(increment_counter)
print("Counter value: ", counter)
Local VS Cluster
上述代码的表现是不确定的,或许可以按照你预想的方式运行。为了运行jobs,Spark将RDD的操作处理分解成任务,每一个都是一个执行者。在执行之前,Spark会计算任务task的闭包。闭包即在执行者执行RDD操作时,其执行所需的变量和方法对其是可见的。这些闭包会被序列化然后送到没一个执行者上边。
在发送到执行者的闭包中的变量,现在是原始的副本,当counter 被引用时,他不再是driver上的counter。在driver的内存中还有一个counter ,但是其对executer(执行者)是不可见的。所以,counter最后的值还是0,因为所有对counter执行的操作都是在序列化的闭包中执行的。
在local模式中,在某些场景中,foreach函数的执行会在相同的JVM中,或许会引用到相同的原始的counter,或许会真的uodate它。
确保定义的行为在这些场景中,应该利用accumulator。在Spark中,Accumulator提供一种安全的更新变量的方式,挡在集群中执行时。
通常情况下,在利用loops或local结构定义方法时,闭包不应该改变全局变量的值。Spark,没有定义或者保证在闭包之外修改变量的行为。有一些代码,活血在local模式下可以执行,但是那只是意外,这些低吗在分布式的情况下不会跟期待的那样执行。
5.5 输出RDD的元素
rdd.foreach(println)
or rdd.map(println)
.,在单机模式下,这有可能会会按照所期待的那样输出。但是在集群下,并不行。
输出driver中的所有元素利用collect(),可能会导致内存溢出,因为collect()会将所有的Rdd放到单机上。如果只是想输出RDD的少数部分元素,一种安全的方式是利用take()。