一、What is Apache Spark?
- Apache Spark是一种用于大规模数据处理的快速通用引擎。
- Written in Scala
- 运行在JVM中的函数式编程语言
- Spark shell
- 交互式学习、数据探索或特别分析
- Python and Scala
- Spark applications
- 用于大规模数据处理
- Python, Scala, and Java
1、Spark栈
- Spark提供了一个构建在core Spark上的库堆栈
- Core Spark提供了Spark的基本抽象:弹性分布式数据集(RDDs)
- Spark SQL适用于结构化数据
- MLlib支持可扩展的机器学习
- Spark Streaming应用程序实时处理数据
- GraphX与图形和图形并行计算一起工作
2、Spark SQL
- Spark SQL是一个用于处理结构化数据的Spark库
- Spark SQL提供了什么?
- 数据帧(DataFrame)和数据集API(Dataset API)
- Spark应用开发的主要入口
- 数据帧(DataFrame)和数据集(Dataset API)是表示结构化的抽象数据
- Catalyst optimizer——一个可扩展的优化框架
- 一个SQL引擎和命令行接口
二、启动Spark Shell
1、关于Spark Shell
- Spark shell提供了一个交互式的Spark环境
- 通常被称为:REPL, or Read/Evaluate/Print Loop
- 用于学习、测试、数据探索或特别分析
- 可以使用Python或Scala运行Spark shell
- 通常在网关节点上运行Spark shell
2、启动Spark Shell
在Cloudera集群中,启动Spark shell的命令有两种,分别为:
- Python的pyspark
- Scala的spark-shell
Spark shell有许多不同的启动选项,包括:
- master:指定要连接的集群
- JAR:附加的JAR文件
- py-files:附加的Python文件(仅Python)
- name::Spark Application UI用于此应用程序的名称
- 默认为PySparkShell (Python)或Spark shell (Scala)
- help:显示所有可用的shell选项
$ pyspark --name "My Application"
3、Spark集群选项(1)
- Spark applications can run on these types of clusters
- Apache Hadoop YARN
- Kubernetes
- Apache Mesos
- Spark Standalone
- 它们也可以在本地运行,而不是在集群上运行
- CDH, HDP, and CDP Data Center使用YARN
- CDP Private Cloud and CDP Public Cloud使用Kubernetes
- 指定的集群类型或者URL使用master option(主选项)
4、Spark集群选项(2)
- 设置master option(主选项)以指定集群类型
- yarn
- local[*] runs locally with as many threads as cores (default)
- local[n] runs locally with n threads
- local runs locally with a single thread
$ pyspark --master yarn
$ spark-shell --master yarn
5、Apache Zeppelin
- Apache Zeppelin是一种基于web的笔记本交互数据分析方法。
- 提供与Python、Scala、SQL等协作环境。
三、使用Spark Shell
1、Spark Session(Spark会话窗口)
- Spark API的主入口点是Spark Session
- Spark shell提供了一个预先配置的SparkSession对象,名为Spark
Spark会话窗口(python):
...
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/__ / .__/\_,_/_/ /_/\_\ version spark-version
/_/
Using Python version 3.6.4 (default, Jan 16 2018 18:10:19)
SparkSession available as 'spark'.
In [1]: spark
Out [1]: <pyspark.sql.session.SparkSession at 0x1928b90>
2、使用Spark Session
- SparkSession类提供了用于访问所有的函数和属性
- 例子如下:
- sql:执行一个Spark SQL查询
- catalog:用于管理表的catalog API的入口点
- read:从文件或其他数据源读取数据的函数
- conf:管理Spark配置的对象
- sparkContext:内核Spark API的入口点
3、日志级别(1)
- Spark使用Apache Log4J记录消息
- 信息被标记以及信息的级别(如图)
4、日志级别(2)
- 日志级别有:
- TRACE(跟踪)
- DEBUG(调试)
- INFO (default level in Spark applications)
- WARN (default level in Spark shell)
- ERROR(错误)
- FATAL(致命)
- OFF
5、设置日志级别
- 使用Spark上下文设置当前Spark shell的日志级别
- setLogLevel方法
> spark.sparkContext.setLogLevel("INFO")
四、开始使用数据集(Dataset API)和数据帧(DataFrame)
1、DataFrames and Datasets
- 数据帧和数据集是Spark中数据的主要表示形式
- 数据帧以表格形式表示结构化数据
- DataFrames模型数据类似于RDBMS中的表
- dataframe由松散类型的Row对象集合组成
- 行被组织成由模式描述的列
- 数据集将数据表示为指定类型对象的集合
- 数据集是强类型的:在编译时强制进行类型检查,而不是运行时
- 关联的模式将对象属性映射到表状结构的行和列
- 数据集只在Scala和Java中定义
- DataFrame是Dataset[Row] -包含Row的数据集的别名对象
2、DataFrames and Rows
- 数据帧包含Row对象的集合
- 行包含值的有序集合
- 行值可以是基本类型(如整数、字符串和浮点数)或这些类型的集合(如数组和列表)
- 模式将列名和类型映射到一行中的值
3、例子:创建一个DataFrame(1)
- users.json文本文件包含示例数据
- 每一行包含一个JSON记录,可以包括姓名、年龄和邮政编码字段
- 每一行包含一个JSON记录,可以包括姓名、年龄和邮政编码字段
4、例子:创建一个DataFrame(2)
- Create a DataFrame using spark.read
> usersDF = spark.read.json("users.json")
- Returns the Spark session’s DataFrameReader
- Call json function to create a new DataFrame
5、例子:创建一个DataFrame(3)
- DataFrames总是有一个关联的模式
- DataFrameReader可以从数据中推断模式
- 使用printSchema来显示DataFrame的schema
> usersDF = spark.read.json("users.json")
> usersDF.printSchema()
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
|-- pcode: string (nullable = true)
6、例子:创建一个DataFrame(4)
- show方法以表格格式显示前几行
> usersDF = spark.read.json("users.json")
> usersDF.printSchema()
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
|-- pcode: string (nullable = true)
> usersDF.show()
+----+-------+-----+
| age| name|pcode|
+----+-------+-----+
|null| Alice|94304|
| 30|Brayden|94304|
| 19| Carla|10036|
| 46| Diana| null|
|null|Etienne|94104|
+----+-------+-----+
五、DataFrame操作
- 有两种主要类型的DataFrame操作
- 转换(Transformations)基于现有的DataFrame创建新的DataFrame
- 转换(Transformations)是由应用程序的执行程序并行执行的
- Actions从DataFrame输出数据值
- 输出通常从执行器返回到主Spark程序(称为驱动程序)或保存到文件中
1、DataFrame操作:Actions
- 一些常见的DataFrame的Actions包括:
- count:返回行数
- first:返回第一行(head()的同义词)
- take(n):以数组的形式返回前n行(head(n)的同义词)
- show(n):以表格形式显示前n行(默认为20行)
- collect:以数组的形式返回DataFrame中的所有行
- write:将数据保存到文件或其他数据源中
示例:take Action
python:
> usersDF = spark.read.json("users.json")
> users = usersDF.take(3)
[Row(age=None, name=u'Alice', pcode=u'94304'),
Row(age=30, name=u'Brayden', pcode=u'94304'),
Row(age=19, name=u'Carla', pcode=u'10036')]
scala:
> val usersDF = spark.read.json("users.json")
> val users = usersDF.take(3)
usersDF: Array[org.apache.spark.sql.Row] =
Array([null,Alice,94304],
[30,Brayden,94304],
[19,Carla,10036])
2、DataFrame操作: Transformations(1)
- 变换(Transformations)在现有DataFrame的基础上创建新的DataFrame
- 新的DataFrame可能具有相同的模式,也可能具有不同的模式
- 转换(Transformations)不返回任何值或数据给驱动程序
- 数据仍然分布在应用程序的各个执行程序中
- 数据在DataFrame中是不可变的
- DataFrame中的数据永远不会被修改
- 当需要改变数据时,使用转换(Transformations)创建一个新的DataFrame
3、DataFrame操作: Transformations(2)
- 常见的转换(Transformations)包括:
- select:只包含指定的列
- where:只包含指定表达式为true的行(filter的同义词)
- orderBy:行按指定的列排序(sort的同义词)
- join:连接指定列上的两个DataFrames
- limit(n):创建一个只有前n行的DataFrame
4、示例:select and where Transformations
> nameAgeDF = usersDF.select("name","age")
> nameAgeDF.show()
+-------+----+
| name| age|
+-------+----+
| Alice|null|
|Brayden| 30|
| Carla| 19|
| Diana| 46|
|Etienne|null|
+-------+----+
> over20DF = usersDF.where("age > 20")
> over20DF.show()
+---+-------+-----+
|age| name|pcode|
+---+-------+-----+
| 30|Brayden|94304|
| 46| Diana| null|
+---+-------+-----+
5、Defining Queries(定义查询)
- 转换(Transformations)后面跟着Actions即是查询
> nameAgeDF = usersDF.select("name","age")
> nameAgeOver20DF = nameAgeDF.where("age > 20")
> nameAgeOver20DF.show()
+---+-------+
|age| name|
+---+-------+
| 30|Brayden|
| 46| Diana|
+---+-------+
6、串联Transformations
- 查询中的转换(Transformations)可以链接在一起
- 这两个例子以相同的方式执行相同的查询
- 差别只是句法上
python:
分开写法:
> nameAgeDF = usersDF.select("name","age")
> nameAgeOver20DF = nameAgeDF.where("age > 20")
> nameAgeOver20DF.show()
串联写法:
> usersDF.select("name","age").where("age > 20").show()
scala:
分开写法:
> val nameAgeDF = usersDF.select("name","age")
> val nameAgeOver20DF = nameAgeDF.where("age > 20")
> nameAgeOver20DF.show
串联写法:
> usersDF.select("name","age").where("age > 20").show
六、Essential Points(基本要点)
- Apache Spark是一个分析和处理大数据的框架
- Python和Scala Spark shell是用于交互执行Spark的命令行
- Spark应用在shell外以批处理方式运行
- DataFrames通过应用模式(schema)以表格形式表示结构化数据
- DataFrames的操作类型:
- Transformations:转换(Transformations)通过转换现有数据创建新DataFrames
- Actions:Actions收集DataFrame中的值,并保存它们或将它们返回给Spark驱动程序
- 查询(query)由一系列的转换(Transformations)和操作(Actions)组成
七、实践练习:使用Apache Spark Shell探索DataFrames
1、查看Spark文档
1、请通过浏览器http://spark.apache.org/docs/2.4.0/查看Spark文档。
2、从编程指南菜单中,选择SQL、DataFrames和dataset。简要回顾指南和书签页,以供以后参考。
3、从API文档菜单中选择Scala或Python,这取决于你的语言偏好。将API页面标记为书签,以便在类中使用。后面的练习将参考此文档。
4、如果您正在查看Scala API,请注意包名显示在左侧。使用搜索框或向下滚动查找org.apache.spark.sql包。这个包包含了你将在本课程中使用的大多数类和对象。特别要注意Dataset类。尽管本练习的重点是DataFrames,但请记住DataFrames只是Row对象的dataset的别名。因此,您将在本练习中练习的所有DataFrame操作都记录在Dataset类中。
5、如果您正在查看Python API,请定位pyspark。sql模块。这个模块包含了你将在本课程中使用的大多数类。顶部是模块中的一些关键类。查看DataFrame类的API;这些是您将在本练习中练习的操作。
2、启动Spark Shell
您可以选择使用Scala或Python来完成本练习中的其余步骤。
注意Spark Shell提示符
为了帮助您跟踪一个Spark命令是Python还是Scala,提示符在这里显示为pyspark>或scala>。有些命令在Scala和Python中是相同的。这些将以>显示;向提示。根据您使用的Python或Scala版本以及使用的命令号,shell中实际显示的提示符会有所不同。
6、如果您的远程桌面上没有打开终端窗口,请现在启动一个。
7、在终端窗口中,启动Spark shell。启动Python shell或Scala shell,而不是两者都启动。
要启动Python shell,请使用pyspark命令。
$ pyspark
使用spark-shell命令启动Scala shell。
$ spark-shell
您可能会得到几个WARN消息,您可以忽略这些消息。
8、Spark为您创建一个名为Spark的SparkSession对象。确保对象存在。如果您正在使用Python,请使用下面的第一个命令,如果您正在使用Scala,请使用第二个命令。(你只需要用Python或Scala完成练习。)
pyspark> spark
scala> spark
Python将显示有关spark对象的信息,例如:
<pyspark.sql.session.SparkSession at address>
Scala会以不同的格式显示类似的信息:
org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@address
注意:在后面的说明中,Python和Scala命令都会显示出来,但不会明确说明;Python shell命令是蓝色的,前面是pyspark>; Scala shell命令是红色的,后面是scala>。
9、通过命令补全,您可以看到所有可用的Spark会话方法:(星号后面有一个点),然后是TAB键。注意:你可以通过输入sys.exit退出Scala shell。要退出Python shell,请按Ctrl+D或输入exit。但是,现在请留在shell中,以完成本练习的其余部分。
3、读取和显示一个JSON文件
10、打开一个新的终端窗口(除了运行Spark shell的终端)。
11、查看您将使用的简单文本文件:$DEVDATA/devices.json。您可以在Pluma编辑器中查看该文件,或者启动一个新的终端窗口,然后使用less命令。(不要修改文件。)此文件包含Loudacre支持的每个设备的记录。例如:
{"devnum":1,"release_dt":"2008-10-21T00:00:00.000-07:00","make":"Sorrento","model":"F00L","dev_type":"phone"}
注意前几条记录中的字段名和值的类型。
12、将数据文件上传到HDFS的“/devsh_loudacre”目录。
$ hdfs dfs -put $DEVDATA/devices.json /devsh_loudacre/
13、在Spark shell中,根据设备创建一个新的DataFrame.json文件。
pyspark> devDF = spark.read.json("/devsh_loudacre/devices.json")
scala> val devDF = spark.read.json("/devsh_loudacre/devices.json")
14、Spark还没有读取文件中的数据,但是它已经扫描了文件以推断模式。查看模式,注意列名与JSON文件中的记录字段名匹配。
pyspark> devDF.printSchema()
scala> devDF.printSchema
15、使用show函数显示DataFrame中的数据。如果不传递参数给show, Spark将显示DataFrame中的前20行。对于这一步,显示前5行。注意,数据以表格形式显示,使用模式中定义的列名。
pyspark> devDF.show(5)
scala> devDF.show(5)
注意:与许多Spark查询一样,无论您使用的是Scala还是Python,该命令都是相同的。
16、show和printSchema操作是actions—也就是说,它们从分布式DataFrame返回一个值给Spark驱动程序。这两个函数都在一个格式良好的表中显示数据。这些函数用于shell中的交互使用,但不允许实际处理返回的数据。尝试使用take操作,它返回Row对象的数组(Scala)或列表(Python)。您可以通过遍历集合来显示数据。
pyspark> rows = devDF.take(5)
pyspark> for row in rows: print(row)
scala> val rows = devDF.take(5)
scala> rows.foreach(println)
17、查询id为17的DataFrame。使用count操作返回DataFrame中的项数。
> devDF.count()
18、DataFrame转换通常返回另一个DataFrame。尝试使用选择转换来返回一个只有make和model列的DataFrame,然后显示它的模式。注意,模式中只有选定的列。
pyspark> makeModelDF = devDF.select("make","model")
pyspark> makeModelDF.printSchema()
scala> val makeModelDF = devDF.select("make","model")
scala> makeModelDF.printSchema
19、查询是一系列一个或多个转换,后面跟着一个操作。在调用action操作之前,Spark不会执行查询。使用show操作显示系列中最后的DataFrame的前20行。
pyspark> makeModelDF.show()
scala> makeModelDF.show
20、查询中的转换可以链接在一起。使用select和where执行单个命令显示查询结果。生成的DataFrame将只包含列devnum、make和model,以及make为Ronin的行。
pyspark> devDF.select("devnum","make","model").where("make = 'Ronin'").show()
scala> devDF.select("devnum","make","model").where("make = 'Ronin'").show