目录
二、RDD V.S. DataFrame V.S. Dataset
一、SparkSQL的编程模型
1.1 编程模型简介
主要通过两种⽅式操作
SparkSQL
,⼀种就是
SQL
,另⼀种为
DataFrame
和
Dataset
。
- SQL
SQL不⽤多说,就和
Hive
操作⼀样,但是需要清楚⼀点的时候,
SQL
操作的是表,所以要想⽤
SQL
进⾏操作,就需要将SparkSQL
对应的编程模型转化成为⼀张表才可以。
同时⽀持,通⽤sql
和
hiveql
。
- DataFrame和Dataset
DataFrame和
Dataset
是
SparkSQL
中的编程模型。
DataFrame
和
Dataset
我们都可以理解为是⼀张
mysql
中 的⼆维表,表有什么?表头,表名,字段,字段类型。RDD
其实说⽩了也是⼀张⼆维表,但是这张⼆维表相 ⽐较于DataFrame
和
Dataset
却少了很多东⻄,⽐如表头,表名,字段,字段类型,只有数据。
Dataset
是在
spark1.6.2
开始出现出现的
api
,
DataFrame
是
1.3
的时候出现的,早期的时候
DataFrame
叫 SchemaRDD,
SchemaRDD
和
SparkCore
中的
RDD
相⽐较,就多了
Schema
,所谓约束信息,元数据信息。
⼀般的,将RDD
称之为
Spark
体系中的第⼀代编程模型;
DataFrame
⽐
RDD
多了⼀个
Schema
元数据信息,被称之为Spark
体系中的第⼆代编程模型;
Dataset
吸收了
RDD
的优点
(
强类型推断和强⼤的函数式编程
)
和 DataFrame中的优化
(SQL
优化引擎,内存列存储
)
,成为
Spark
的最新⼀代的编程模型。
二、RDD V.S. DataFrame V.S. Dataset
2.1 RDD
弹性分布式数据集,是Spark
对数据进⾏的⼀种抽象,可以理解为
Spark
对数据的⼀种组织⽅式,更简单些说, RDD就是⼀种数据结构,⾥⾯包含了数据和操作数据的⽅法
a. 弹性:
数据可完全放内存或完全放磁盘,也可部分存放在内存,部分存放在磁盘,并可以⾃动切换 RDD出错后可⾃动重新计算(通过⾎缘⾃动容错)
可
checkpoint
(设置检查点,⽤于容错),可
persist
或
cache
(缓存) ⾥⾯的数据是分⽚的(也叫分区,partition
),分⽚的⼤⼩可⾃由设置和细粒度调整
b. 分布式:
RDD中的数据可存放在多个节点上
c.
数据集:
数据的集合,没啥好说的
相对于与DataFrame
和
Dataset
,
RDD
是
Spark
最底层的抽象,⽬前是开发者⽤的最多的,但逐步会转向
DataFrame
和
Dataset
(当然,这是
Spark
的发展趋势)
2.2DataFrame
DataFrame:理解了
RDD
,
DataFrame
就容易理解些,
DataFrame
的思想来源于
Python
的
pandas
库,
RDD
是⼀ 个数据集,DataFrame
在
RDD
的基础上加了
Schema
(描述数据的信息,可以认为是元数据,
DataFrame
曾经就有 个名字叫SchemaRDD
)
假设
RDD
中的两⾏数据⻓这样
.:
![](https://img-blog.csdnimg.cn/20210816195609718.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0N5QXVyb3Jh,size_16,color_FFFFFF,t_70)
从上⾯两个图可以看出,DataFrame
⽐
RDD
多了⼀个表头信息(
Schema
),像⼀张表了,
DataFrame
还配套了新 的操作数据的⽅法,DataFrame API
(如
df.select())
和
SQL(select id, name from xx_table where ...)
。
有了DataFrame
这个⾼⼀层的抽象后,我们处理数据更加简单了,甚⾄可以⽤
SQL
来处理数据了,对开发者来 说,易⽤性有了很⼤的提升。
不仅如此,通过DataFrame API
或
SQL
处理数据,会⾃动经过
Spark
优化器(
Catalyst
)的优化,即使你写的程 序或SQL
不⾼效,也可以运⾏的很快,很爽吧!
2.3Dataset
相对于RDD,Dataset提供了强类型⽀持,也是在RDD的每⾏数据加了类型约束
使⽤Dataset API的程序,会经过Spark SQL的优化器进⾏优化
⽬前仅⽀持Scala、Java API,尚未提供Python的API(所以⼀定要学习Scala),相⽐DataFrame,Dataset提供 了编译时类型检查,对于分布式程序来讲,提交⼀次作业太费劲了(要编译、打包、上传、运⾏),到提交到集群 运⾏时才发现错误,实在是想骂⼈,这也是引⼊Dataset的⼀个重要原因。
使⽤
DataFrame
的代码中
json
⽂件中并没有
score
字段,但是能编译通过,但是运⾏时会报异常!如下图代码所 示.
⽽使⽤Dataset实现,会在IDE中就报错,出错提前到了编译之前
三、SparkSQL的编程⼊⼝
在SparkSQL
中的编程模型,不在是
SparkContext
,但是创建需要依赖
SparkContext
。
SparkSQL
中的编程模 型,在spark2.0
以前的版本中为
SQLContext
和
HiveContext
,
HiveContext
是
SQLContext
的⼀个⼦类,提供
Hive 中特有的⼀些功能,⽐如row_number
开窗函数等等,这是
SQLContext
所不具备的,在
Spark2.0
之后将这两个进 ⾏了合并——
SparkSession
。
SparkSession
的构建需要依赖
SparkConf
或者
SparkContext
。使⽤⼯⼚构建器 (Builder⽅式
)
模式创建
SparkSession
。
3.1 SparkSQL基本编程
创建SparkSQL的模块
创建⼯程省略,引⼊PomSparkSQL编程初体验
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>${spark.version}</version>
</dependency> <dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
3.2 SparkSQL编程初体验
- SparkSession的构建
val spark = SparkSession.builder()
.appName("SparkSQLOps")
.master("local[*]")
//.enableHiveSupport()//⽀持hive的相关操作
.getOrCreate()
- 基本编程
数据
{"name":"Michael", "age":10, "height": 168.8, "province": "广东"}
{"name":"Andy", "age":30, "height": 168.8, "province": "福建"}
{"name":"Justin", "age":19, "height": 169.8, "province": "浙江"}
{"name":"王启峰", "age":32, "height": 188.8, "province": "广东"}
{"name":"John", "age":10, "height": 168.8, "province": "河南"}
{"name":"Domu", "age":19, "height": 179.8, "province": "浙江"}
{"name":"郭英伟", "age":13, "height": 178.8, "province": "福建"}
{"name":"王 荃", "age":18, "height": 175.8, "province": "河南"}
{"name":"米 鼎", "age":19, "height": 190.8, "province": "广东"}
代码
package org.aurora.sparkSQL_01
import org.apache.spark.sql.{Column, DataFrame, SparkSession}
object Dfef {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName("SparkSQLOps")
.master("local[*]")
// .enableHiveSupport()//⽀持hive的相关操作
.getOrCreate()
//加载数据
val pdf:DataFrame = spark.read.json("file:///E:/data/spark/sql/people.json")
//⼆维表结构
pdf.printSchema()
//数据内容 select * from tbl
pdf.show()
//具体的查询 select name, age from tbl
pdf.select("name", "age").show()
import spark.implicits._//导⼊sparksession中的隐式转换操作,增强sql的功能
pdf.select($"name",$"age").show()
//列的运算,给每个⼈的年龄+10 select name, age+10,height-1 from tbl
pdf.select($"name",$"height" - 1, new Column("age").+(10)).show()
//起别名 select name, age+10 as age,height-1 as height from tbl
pdf.select($"name",($"height" - 1).as("height"), new Column("age").+ (10).as("age")).show()
//做聚合统计 统计不同年龄的⼈数 select age, count(1) counts from tbl group by age
pdf.select($"age").groupBy($"age").count().show()
//条件查询 获取年龄超过18的⽤户 select * from tbl where age > 18
// pdf.select("name", "age", "height").where($"age".>(18)).show()
pdf.select("name", "age", "height").where("age > 18").show()
//sql
// pdf.registerTempTable()//在spark2.0之后处于维护状态,使⽤createOrReplaceTempView
/*
从使⽤范围上说,分为global和⾮global
global是当前SparkApplication中可⽤,⾮global只在当前SparkSession中可⽤
从创建的⻆度上说,分为createOrReplace和不Replace
createOrReplace会覆盖之前的数据
create不Replace,如果视图存在,会报错
*/
pdf.createOrReplaceTempView("people")
spark.sql(
"""
|select
| age,
| count(1) as countz
|from people
|group by age
""".stripMargin).show
spark.stop()
}
}