Spark的客户端(Driver)有两种:Spark Submit和Spark Shell。这两种客户端相同点都是维护一个Spark Context对象,来向Spark集群提交任务;不同点是Spark Submit只能提交任务,不能交互,而Spark Shell是一个命令行工具,即可以提交任务,还可以人机交互。本节就来介绍Spark Shell客户端的使用。
1.Spark Shell的两种运行模式
Spark Shell客户端有两种运行模式:本地模式和集群模式。本地模式不需要连接到Spark集群上;集群模式需要连接到Spark集群。
1.1 本地模式
由于本地模式不需要连接到Spark集群上,所以启动只需要输入以下命令即可:
[root@spark111 ~]# spark-shell
根据输出的日志可以看出当前的运行模式是本地模式:
Spark context available as 'sc' (master = local[]*, app id = local-1528644845363).
Welcome to
____ __
/ / ___ _____/ /__
\ / _ / _ `/ / '/
// ./_,// //_\ version 2.1.0
/_/Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144)
Type in expressions to have them evaluated.
Type :help for more information.scala>
1.2集群模式
由于集群模式需要连接到Spark集群上,所以启动时需要指定Spark Master节点:
[root@spark111 ~]# spark-shell --master spark://spark111:7077
根据输出的日志可以看出当前的运行模式是集群模式:
Spark context available as 'sc' (master = spark://spark111:7077,
app id = app-20180610233813-0000).Welcome to
____ __
/ / ___ _____/ /__
\ / _ / _ `/ / '/
// ./_,// //_\ version 2.1.0
/_/Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144)
Type in expressions to have them evaluated.
Type :help for more information.scala>
2.Spark Shell选项和算子介绍
2.1Spark Shell帮助信息
[root@spark111 ~]# spark-shell --help
2.2Spark Shell常用选项
--master MASTER_URL 指定Spark集群的地址
--executor-memory MEM 指定每个Executor的内存,默认1GB
--total-executor-cores NUM 指定所有Executor所占的核数
--num-executors NUM 指定Executor的个数
--help, -h 显示帮助信息
--version 显示版本号
2.3SparkContext(简写为sc)对象的常用算子
进入Spark Shell环境下,输入sc.
,按Tab键可以列出sc对象所有可用的算子:
这些算子分为两类:Transformation和Action。其中Transformation算子返回的结果是RDD(弹性分布式数据集),不会触发计算;而Action会触发计算。这里先列出几个常用的算子,其他的后面用到了再专门详细介绍:
常用的Transformation算子:
- textFile 读取文本文件到一个字符串数组中,一行作为一个元素
- flatMap 展平,将多行变为一行
- split 分词,按指定分割符分词
- map 映射,Map
- reduceByKey 按Key聚合,Reduce
常用的Action算子:
- collect 将结果放在一个集合中显示,触发计算
3.在Spark Shell中开发程序
例子:使用Spark Shell开发WordCount程序。
3.1从本地文件读入数据,将结果直接打印在屏幕上
[root@spark111 input]# cat /root/input/data.txt
I love Beijing
I love China
Beijing is the capital of China[root@spark111 ~]# spark-shell --master spark://spark111:7077
scala> sc.textFile("file:///root/input/data.txt")
.flatMap(.split(" "))
.map((,1))
.reduceByKey(+)
.collect
res0: Array[(String, Int)] = Array((is,1), (love,2), (capital,1),
(Beijing,2), (China,2), (I,2), (of,1), (the,1))
3.2从本地文件读入数据,将结果输出到到本地文件
[root@spark111 ~]# spark-shell --master spark://spark111:7077
scala> sc.textFile("file:///root/input/data.txt")
.flatMap(.split(" "))
.map((,1))
.reduceByKey(+)
.saveAsTextFile("file:///root/output/spark/wc")[root@spark111 ~]# cd /root/output/spark/wc
[root@spark111 wc]# ls
part-00000 part-00001 _SUCCESS
[root@spark111 wc]# cat part-00000
(is,1)
(love,2)
(capital,1)
(Beijing,2)
[root@spark111 wc]# cat part-00001
(China,2)
(I,2)
(of,1)
(the,1)
3.3从HDFS读入数据,将结果打印在屏幕上
scala> sc.textFile("hdfs://spark111:9000/input/data.txt")
.flatMap(.split(" "))
.map((,1))
.reduceByKey(+)
.collect
res4: Array[(String, Int)] = Array((is,1), (love,2), (capital,1),
(Beijing,2), (China,2), (I,2), (of,1), (the,1))
3.4从HDFS读入数据,将结果输出到HDFS
scala> sc.textFile("hdfs://spark111:9000/input/data.txt")
.flatMap(.split(" "))
.map((,1))
.reduceByKey(+)
.saveAsTextFile("hdfs://spark111:9000/output/spark/wc")
[root@spark111 ~]# cd /root/training/hadoop-2.7.3/bin/
[root@spark111 bin]# ./hdfs dfs -ls /output/spark/wc
Found 3 items
-rw-r--r-- 1 root supergroup 0 2018-06-11 23:04 /output/spark/wc/_SUCCESS
-rw-r--r-- 1 root supergroup 40 2018-06-11 23:04 /output/spark/wc/part-00000
-rw-r--r-- 1 root supergroup 31 2018-06-11 23:04 /output/spark/wc/part-00001
[root@spark111 bin]# ./hdfs dfs -cat /output/spark/wc/part-00000
(is,1)
(love,2)
(capital,1)
(Beijing,2)
[root@spark111 bin]# ./hdfs dfs -cat /output/spark/wc/part-00001
(China,2)
(I,2)
(of,1)
(the,1)
3.5单步运行WordCount程序
scala> val rdd1 = sc.textFile("file:///root/input/data.txt")
rdd1: org.apache.spark.rdd.RDD[String] = file:///root/input/data.txt
MapPartitionsRDD[1] at textFile at:24
scala> rdd1.collect
res0: Array[String] = Array(I love Beijing, I love China,
Beijing is the capital of China)scala> val rdd2 = rdd1.flatMap(_.split(" "))
rdd2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2]
at flatMap at:26
scala> rdd2.collect
res1: Array[String] = Array(I, love, Beijing, I, love, China, Beijing,
is, the, capital, of, China)scala> val rdd3 = rdd2.map((_,1))
rdd3: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[3]
at map at:28
scala> rdd3.collect
res2: Array[(String, Int)] = Array((I,1), (love,1), (Beijing,1), (I,1),
(love,1), (China,1), (Beijing,1), (is,1), (the,1), (capital,1), (of,1), (China,1))scala> val rdd4 = rdd3.reduceByKey(+)
rdd4: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[4]
at reduceByKey at:30
scala> rdd4.collect
res3: Array[(String, Int)] = Array((is,1), (love,2), (capital,1),
(Beijing,2), (China,2), (I,2), (of,1), (the,1))
通过单步执行WordCount程序,可以清楚地看到每一步的计算结果,这可以帮助我们更好的理解程序的执行过程。这种单步执行的方式也是开发测试Spark程序常用的手段。
至此,Spark Shell客户端的使用已经介绍完毕,祝你玩的愉快!