Spark从入门到精通8:Spark客户端之Spark Shell的使用

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对象所有可用的算子:

image

这些算子分为两类: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客户端的使用已经介绍完毕,祝你玩的愉快!

你可能感兴趣的:(Spark从入门到精通8:Spark客户端之Spark Shell的使用)