因为Scala才刚刚开始学习,仍是对python更为熟悉,所以在这记录一下本身的学习过程,主要内容来自于spark的官方帮助文档
文章主要是翻译了文档的内容,但也在里边加入了一些本身在实际操做中遇到的问题及解决的方案,和一些补充的小知识,一块儿学习。算法
环境:Ubuntu 16.04 LTS,Spark 2.0.1, Hadoop 2.7.3, Python 3.5.2,shell
利用spark shell进行交互式分析apache
1. 基础api
首先打开spark与python交互的API缓存
$ cd /usr/local/spark
$ ./bin/pyspark
Spark最重要的一个概念就是RDD(Resilient Distributed Dataset),弹性分布式数据集。RDD能够利用Hadoop的InputFormats建立,或者从其余RDD转换。app
这里,做为入门,咱们利用spark安装后文件夹中自带的README.md(此文件位置为/usr/local/spark/README.md)文件做为例子,学习如何建立一个新的RDD。分布式
建立新的RDD:函数
>>> textFile = sc.textFile(“README.md”)
RDD支持两种类型的操做,actions和transformations:
actions: 在数据集上运行计算后返回值
transformations: 转换, 从现有数据集建立一个新的数据集
RDD能够有执行一系列的动做(actions),这些动做能够返回值(values),转换(transformations),或者指向新的RDD的指针。下边学习RDD的一些简单的动做:
>>> textFile.count() #计数,返回RDD中items的个数,这里就是README.md的总行# 数
99
>>> textFile.first() #RDD中的第一个item,这里就是文件README.md的第一行
u'# Apache Spark'
注意:若是以前是从/usr/local/spark启动pyspark,而后读取README.md文件的,若是执行count语句,会出现如下错误:
py4j.protocol.Py4JJavaError: An error occurred while calling z:org.apache.spark.api.python.PythonRDD.collectAndServe.
: org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: hdfs://localhost:9000/user/spark/README.md
这是由于在使用相对路径时,系统默认是从hdfs://localhost:9000/目录下读取README.md文件的,可是README.md文件并不在这一目录下,因此sc.textFile()必须使用绝对路径,此时代码修改成:
>>> textFile = sc.textFile(“file:///usr/local/spark/README.md”)99
下边尝试使用一个转换(transformation)。例如,使用filter这一转换返回一个新的RDD,这些RDD中的items都含有“Spark”字符串。
>>> linesWithSpark = textFile.filter(lambda line: “Spark” in line)
咱们还能够将actions和transformation连接起来:
>>> textFile.filter(lambda line: “Spark” in line).count() #有多好行含有“Spark”这一字符串
19
2. 更多的RDD操做
利用RDD的动做和转换可以完成不少复杂的计算。例如,咱们但愿找到含有最后单词的一句话:
>>> textFile.map(lambda line: len(line.split())).reduce(lambda a, b: a if (a>b) elseb)22
这个语句中,map函数将len(line.split())这一语句在全部line上执行,返回每一个line所含有的单词个数,也就是将line都map到一个整数值,而后建立一个新的RDD。而后调用reduce,找到最大值。map和reduce函数里的参数是python中的匿名函数(lambda),事实上,咱们这里也能够传递python中更顶层的函数。好比,咱们先定义一个比较大小的函数,这样咱们的代码会更容易理解:
>>> defmax(a, b):
. . .if a >b:
. . .returna
. . .else:
. . .returnb
. . .>>> textFile.map(lambdaline: len(line.split())).reduce(max)22
Hadoop掀起了MapReduce的热潮。在spark中,可以更加容易的实现MapReduce
>>> wordCounts = textFile.flatMap(lambda line: line.split()).map(lambda word: (word, 1)).reduceByKey(lambda a, b: a+b)
上述语句中,利用flatMap, map和reduceByKey三个转换,计算文件README.md中每一个单词出现的个数,并返回一个新的RDD,每一个item的格式为(string, int),即单词和对应的出现次数。其中,
flatMap(func):与map类似,可是每一个输入的item可以被map到0个或者更多的输出items上,也就是说func的返回值应当是一个Seq,而不是一个单独的item,上述语句中,匿名函数返回的就是一句话中所含的每一个单词
reduceByKey(func):能够做用于使用“键-值”(K, V)形式存储的数据集上并返回一组新的数据集(K, V),其中,每一个键的值为聚合使用func操做的结果,这里至关于python中字典的含义。上述语句中,至关于当某个单词出现一次时,就在这个单词的出现次数上加1,每一个单词就是一个Key,reducByKey中的匿名函数计算单词的出现次数。
要收集上述语句的计算结果,可使用collect这一动做:
>>>wordCounts.collect()
[(u'when', 1), (u'R,', 1), (u'including', 3), (u'computation', 1), ...]
3. 缓存Caching
Spark也支持将数据集存入集群范围的内存缓存中。这对于须要进行重复访问的数据很是有用,好比咱们须要在一个小的数据集中执行查询操做,或者须要执行一个迭代算法(例如PageRank)。下面,利用以前命令中获得的linesWithSpark数据集,演示缓存这一操做过程:
>>>linesWithSpark.cache()
PythonRDD[26] at RDD at PythonRDD.scala:48
>>>linesWithSpark.count()19
>>>linesWithSpark.count()19
利用Spark去缓存一个100行的文件可能并没什么意义。可是有趣的是,这一系列的操做能够用于很是大的数据集上,甚至含有成千上万的节点的数据集。
4. 自含式应用程序(self-contained applications)
假设咱们但愿利用Spark API写一个自含式应用程序,咱们能够利用Scala,Java或者Python完成。
下边,简单介绍一下怎样利用Python API (PySpark)写一个应用程序,命名为SimpleApp.py.
在spark所在目录下输入:
./bin/spark-submit --master local[4] SimpleApp.py
输出为:
Lines with a: 61, Lines with b: 27
此外,Spark自带不少例子,能够在spark目录下输入下列指令查看:
#For Scala and Java, use run-example:
./bin/run-example SparkPi#For Python examples, use spark-submit directly:
./bin/spark-submit examples/src/main/python/pi.py#For R examples, use spark-submit directly:
./bin/spark-submit examples/src/main/r/dataframe.R