Spark SQL DataFrame 算子

Spark SQL DataFrame 算子

DataFrame 与 Dataset API 提供了简单的、统一的并且更富表达力的 API ,简言之,与 RDD 与算子的组合相比,DataFrame 与 Dataset API 更高级。

DataFrame 不仅可以使用 SQL 进行查询,其自身也具有灵活的 API 可以对数据进行查询,与 RDD API 相比,DataFrame API 包含了更多的应用语义,所谓应用语义,就是能让计算框架知道你的目标的信息,这样计算框架就能更有针对性地对作业进行优化,本课时主要介绍如何创建DataFrame 以及如何利用 DataFrame 进行查询。

创建DataFrame

前面我们用了 SparkSession 的 read API 从 Parquet 文件创建 DataFrame,其实创建 DataFrame 的方法还有很多。毫不夸张地说,DataFrame 的创建途径异常丰富,为什么这么说呢?

Spark 支持多种数据源,按照数据来源进行划分,这些数据源可以分为如下几个大类:Driver 端自定义的数据结构、(分布式)文件系统、关系型数据库 RDBMS、关系型数据仓库、NoSQL 数据库,以及其他的计算引擎,此外还支持由 RDD 通过类型反射生成,甚至还可以通过流式数据源生成,

对于文件系统而言,Json、Parquet、ORC 等文件是自带 Schema 的,而那些无 Schema 的数据源,DataFrame 会自己生成 Schema

image-20240731150753495

从 Driver 创建 DataFrame

在 Driver 端,Spark 可以直接从数组、元组、映射等数据结构创建 DataFrame。使用这种方式创建的 DataFrame 通常数据量有限,因此这样的 DataFrame 往往不直接参与分布式计算,而是用于辅助计算或是数据探索。尽管如此,学习这部分知识点还是非常必要的,因为它可以帮我们更直观地理解 DataFrame 与 RDD 的关系。

在数据表示(Data Representation)上,相比 RDD,DataFrame 仅仅是多了一个 Schema。甚至可以说,DataFrame 就是带 Schema 的 RDD。因此,创建 DataFrame 的第一种方法,就是先创建 RDD,然后再给它“扣上”一顶 Schema 的“帽子”。

createDataFrame 方法

从本地数据结构创建 RDD,我们用的是 SparkContext 的 parallelize 方法,而给 RDD“扣帽子”,我们要用到 SparkSession 的 createDataFrame 方法。

为了创建 RDD,我们先来定义列表数据 seq。seq 的每个元素都是二元元组,元组第一个元素的类型是 String,第二个元素的类型是 Int。有了列表数据结构,接下来我们创建 RDD,如下所示

import org.apache.spark.rdd.RDD
val seq: Seq[(String, Int)] = Seq(("Bob", 14), ("Alice", 18))
val rdd: RDD[(String, Int)] = sc.parallelize(seq)

有了 RDD 之后,我们来给它制作一顶“帽子”,也就是我们刚刚说的 Schema。创建 Schema,我们需要用到 Spark SQL 内置的几种类型,如 StructType、StructField、StringType、IntegerType,等等。

其中,StructType 用于定义并封装 Schema,StructFiled 用于定义 Schema 中的每一个字段,包括字段名、字段类型,而像 StringType、IntegerType 这些 *Type 类型,表示的正是字段类型。为了和 RDD 数据类型保持一致,Schema 对应的元素类型应该是(StringType,IntegerType)。

import org.apache.spark.sql.types.{StringType, IntegerType, StructField, StructType}
val schema:StructType = StructType( Array(
StructField("name", StringType),
StructField("age", IntegerType)
))

好啦,到此为止,我们有了 RDD,也有了为它量身定做的“帽子”Schema。不过,在把帽子扣上去之前,我们还要先给 RDD 整理下“发型”。这是什么意思呢?

createDataFrame 方法有两个形参,第一个参数正是 RDD,第二个参数是 Schema。createDataFrame 要求 RDD 的类型必须是 RDD[Row],其中的 Row 是 org.apache.spark.sql.Row,因此,对于类型为 RDD[(String, Int)]的 rdd,我们需要把它转换为 RDD[Row]。

import org.apache.spark.sql.Row
val rowRDD: RDD[Row] = rdd.map(fileds => Row(fileds._1, fileds._2))

“发型”整理好之后,我们就可以调用 createDataFrame 来创建 DataFrame,代码如下所示

import org.apache.spark.sql.DataFrame
val dataFrame: DataFrame = spark.createDataFrame(rowRDD,schema)

DataFrame 创建好之后,别忘了验证它的可用性,我们可以通过调用 show 方法来做简单的数据探索,验证 DataFrame 创建是否成功。

dataFrame.show
 
/** 结果显示
+----+---+
| name| age|
+----+---+
| Bob| 14|
| Alice| 18|
+----+---+
*/

历尽千辛万苦,我们先是用 Driver 端数据结构创建 RDD,然后再调用 createDataFrame 把 RDD 转化为 DataFrame。你可能会说:“相比用 parallelize 创建 RDD,用 createDataFrame 创建 DataFrame 的方法未免复杂了些,有没有更简便的方法呢?”我们接着往下看。

toDF 方法

其实要把 RDD 转化为 DataFrame,我们并不一定非要亲自制作 Schema 这顶帽子,还可以直接在 RDD 之后调用 toDF 方法来做到这一点。咱们先来看 toDF 函数的用法,然后再去分析,spark.implicits 是如何帮我们轻松创建 DataFrame 的。

import spark.implicits._
val dataFrame: DataFrame = rdd.toDF
dataFrame.printSchema
/** Schema显示
root
|-- _1: string (nullable = true)
|-- _2: integer (nullable = false)
*/

可以看到,我们显示导入了 spark.implicits 包中的所有方法,然后通过在 RDD 之上调用 toDF 就能轻松创建 DataFrame。实际上,利用 spark.implicits,我们甚至可以跳过创建 RDD 这一步,直接通过 seq 列表来创建 DataFrame。

import spark.implicits._
val dataFrame: DataFrame = seq.toDF
dataFrame.printSchema
/** Schema显示
root
|-- _1: string (nullable = true)
|-- _2: integer (nullable = false)
*/

是不是感觉这个方法很简洁、很轻松?不过,你可能会问:“既然有 toDF 这条捷径,一开始干嘛还要花功夫去学步骤繁琐的 createDataFrame 方法呢?”

络上流行过这么一句话:“你的岁月静好,是有人在背后帮你负重前行。”toDF 也是同样的道理,我们之所以能用 toDF 轻松创建 DataFrame,关键在于 spark.implicits 这个包提供了各种隐式方法。

隐式方法是 Scala 语言中一类特殊的函数,这类函数不需要开发者显示调用,函数体中的计算逻辑在适当的时候会自动触发。正是它们在背后默默地帮我们用 seq 创建出 RDD,再用 createDataFrame 方法把 RDD 转化为 DataFrame。

从文件系统创建 DataFrame

Spark 支持多种文件系统,常见的有 HDFS、Amazon S3、本地文件系统,等等。不过无论哪种文件系统,Spark 都要通过 SparkSession 的 read API 来读取数据并创建 DataFrame。所以接下来,我们需要先弄明白 read API 要怎样使用,都有哪些注意事项。

read API 由 SparkSession 提供,它允许开发者以统一的形式来创建 DataFrame,如下图所示

image-20240731151514889

可以看到,要使用 read API 创建 DataFrame,开发者只需要调用 SparkSession 的 read 方法,同时提供 3 类参数即可。这 3 类参数分别是文件格式、加载选项和文件路径,它们分别由函数 format、option 和 load 来指定。

先来看第 1 类参数文件格式,它就是文件的存储格式,如 CSV(Comma Separated Values)、Text、Parquet、ORC、JSON。Spark SQL 支持种类丰富的文件格式,除了这里列出的几个例子外,Spark SQL 还支持像 Zip 压缩文件、甚至是图片 Image 格式。

完整的格式支持,你可以参考下图,或是访问官网给出的列表。在后续的讲解中,我们还会挑选一些常用的数据格式来演示 read API 的具体用法。

image-20240731151619272

文件格式决定了第 2 类参数加载选项的可选集合,也就是说,不同的数据格式,可用的选型有所不同。比如,CSV 文件格式可以通过 option(“header”, true),来表明 CSV 文件的首行为 Data Schema,但其他文件格式就没有这个选型。之后讲到常见文件格式用法时,我们再对其加载选项做具体讲解

值得一提的是,加载选项可以有零个或是多个,当需

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值