Spark着重学习这几点:
- scala 语言
- Spark编程
RDD 的理解使用
DStream 的理解与使用
scala 语言
scala 学习我看的是《scala 编程》,作者是scala语言的开发者Martin Odersky 编写的,作为入门书非常不错。也可以去看英文原版 Programming in Scala ,目前已经出到了第三版。另外熟悉 java 语言的也可以到官方文档去学习:A SCALA TUTORIAL FOR JAVA PROGRAMMERS - Java程序员的 scala 使用教程 。
我自己只是很简单地看完了《scala 编程》的前七章,了解大概的语法之后就开始敲东西尝试去了。但后来翻了下目录发现,从第九章开始是要真正好好看的部分,能深入 scala 语言,所以还是需要继续进行学习的。
scala 语言很简短,相比起 java 的代码量来说缩短了估计三分之一。夸张一点说,如果使用得当,可以缩短到十分之一的代码量。scala 我印象最深刻的就是函数式。举个例子,java 里面定义类是这样的——
class MyClass{
private String str;
private int data;
public MyClass(String str, int data){
this.str = str;
this.data = data;
}
}
然而,scala 里边只需要这样——
class MyClass(str:String,data:int)
由此可见用scala编程真的很省力,但具体实现的时候还是根据实际项目来选择 scala 语言吧。
Spark编程
这里简单提一下 MapReduce 和 Spark 之间的区别(两者都是基于YARN上运行的)。
MapReduce 是 Hadoop 的处理数据的模型,有三个阶段,Map — Shuffle — Reduce。Map 在每个处理机器上进行各自的task计算,每次的计算都要进行一次I/O操作,将结果写入磁盘,非常耗时,不适合迭代函数。
而Spark则是在内存中执行,省略了写入磁盘的操作,适合迭代函数。因此计算速度上来说,Spark将计算的处理速度提高了一百倍。
- RDD
RDD英文全称是Resilient Distributed Datasets,即弹性分布式数据集。官方权威的说明在这里:RDD Programming Guide 。
在高层级中,每个Spark应用程序都由一个驱动程序组成,该程序运行用户的主函数,并在集群上执行各种并行操作。Spark提出的主要抽象概念就是弹性分布式数据集(RDD),它是跨集群节点的一个元素集合,可以并行地执行各种操作。 RDDs 是由 Hadoop 文件系统中的一个文件(或任何其他 Hadoop 支持的文件系统),或者驱动程序中现有的 Scala 集合,转换创建而成。用户还可以让Spark 将一个 RDD 保存在内存中,以便在之后的并行操作中高效地重用。另外,RDDs 还能自动从节点故障中恢复。
Spark 中的第二个抽象概念就是共享变量,可以在并行操作中使用。默认情况下,当 Spark 作为一组任务在不同的节点上并行运行一个函数时,函数中使用的每个变量的副本将会被发送到每个任务中。有时,一个变量需要通过任务分享,或者在任务和驱动程序之间分享。Spark支持两种分享变量,分别是广播变量和累加器(执行统计或者总和计算)。
其实简单说来,我的理解是把RDD当成一个简单的容器,把数据往里一塞,最后流出来的是自己想要的结果。
- Spark程序的工作流程:
从外部创建输入RDD
——> filter() 对 RDD 进行转化操作,定义新的 RDD
——> 告诉 Spark 对需要被重用的中间结果 RDD 执行 persist() 操作
——> 使用 first() 等操作开始一次并行计算,Spark对计算进行优化之后再执行
- 创建 RDD
RDD创建之前要链接到Spark。
val conf = new SparkConf().setAppName(appName).setMaster(master)
new SparkContext(conf)
RDD创建有两种方式,最常见的是文件方式创建RDD。
a. 读取外部数据集(文件、hive 数据库等)
val files = sc.textFile(input) //input为文件路径
b. 驱动程序中的集合(list 、set 等)
- RDD操作
具体看官方给的 API 文档 RDD API - org.apache.spark.rdd,写的非常详细,根据实际需要去官网查询使用。
RDD的操作有两类,下面以集合 {1,2,3,3} 为例写常用的一些操作。
a. 转化操作
操作 | 说明 | 举例 | 结果 |
---|---|---|---|
map() | 处理RDD中的每个元素,返回新的RDD | rdd.map(x => x+1) | {2,3,4,4} |
flatmap() | 处理RDD中每个元素,将每个元素创建为新的RDD,切割单词时使用 | ||
filter() | 按条件过滤RDD中每个元素 | rdd.filter(x > 1) | {2,3,3} |
distinct() | RDD中元素去重 | rdd.distinct() | {1,2,3} |
b. 基本执行操作
操作 | 说明 | 举例 | 结果 |
---|---|---|---|
collect() | 返回RDD中所有的元素 | rdd.collect() | {1,2,3,3} |
count() | 返回RDD集合中元素个数 | rdd.count() | 4 |
reduceByKey() | 返回RDD集合中各个元素出现的次数 | rdd.reduceByKey(_+_) | {(1,1),(2,1),(3,2)} |
foreach() | 对每个元素使用指定函数function(),无返回值 | rdd.foreach(print()) | 控制台输出每个元素 |
实战
编写spark程序,实现这样一个功能,读取一个文本文档,统计其中的单词出现频率并输出。文本文档中的内容如下。
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
思路:使用文档创建RDD,以空格分割每个单词,删除单词尾部的标点符号,使用reduceByKey()进行统计输出。
用 maven 构建项目,添加下述依赖:
org.apache.spark
spark-core_2.11
2.3.1
具体实现的代码:
import org.apache.spark.{SparkContext,SparkConf}
object WordCount {
def main(args: Array[String]):Unit = {
if (args.length < 2){
System.err.println("needs two param
将上述项目打包成 jar 包(我打包的 jar 包叫 scala01.jar),启动 hadoop 的 hdfs,在原生的Spark文件目录下(Spark 去官网下载对应的包,记得配置 /etc/profile 文件,然后 source /etc/profile
使环境生效)命令本地执行:
# spark-submit --class
$ bin/spark-submit --class WordCount ~/Downloads/scala01.jar hdfs://localhost:9000//input/word.txt hdfs://localhost:9000//output01
打开浏览器 localhost:50070 查看是否有输出,如图所示。详细的结果可以在 terminal 的控制台看到,也可以使用dfs -cat
查看。
最后的最后。
有一个地方我不是很明白,我想要让 spark 在本地启动的 yarn 上面跑一下,配置了 {$SPARK_HOME}/conf 中的 spark-env.sh 文件,打开 localhost:8080 查看 YARN 是否执行任务,结果成功输出,但是 accepted 任务还是为空,我理解的是 Spark 并没有部署到本地的YARN上。我配置的文件如下:
# Options read in YARN client/cluster mode
# - SPARK_CONF_DIR, Alternate conf dir. (Default: ${SPARK_HOME}/conf)
# - HADOOP_CONF_DIR, to point Spark towards Hadoop configuration files
# - YARN_CONF_DIR, to point Spark towards YARN configuration files when you use YARN
# - SPARK_EXECUTOR_CORES, Number of cores for the executors (Default: 1).
# - SPARK_EXECUTOR_MEMORY, Memory per Executor (e.g. 1000M, 2G) (Default: 1G)
# - SPARK_DRIVER_MEMORY, Memory for Driver (e.g. 1000M, 2G) (Default: 1G)
export SPARK_CONF_DIR=/home/hadoop/soft/spark-2.3.1-bin-hadoop2.7/conf
export HADOOP_CONF_DIR=/home/hadoop/soft/hadoop/etc/hadoop
export YARN_CONF_DIR=/home/hadoop/soft/hadoop/etc/hadoop
若是有哪位大神知道答案的话,能否评论中告知一下,在此谢谢了。