- 课程地址:spark讲解
- Scala | Spark基础入门 | IDEA配置 | 集群搭建与测试
- Scala | Spark核心编程 | SparkCore | 算子
- Scala | 宽窄依赖 | 资源调度与任务调度 | 共享变量 | SparkShuffle | 内存管理
- Scala | SparkSQL | 创建DataSet | 序列化问题 | UDF与UDAF | 开窗函数
一、SparkSQL
1.SparkSQL介绍
Hive
是 Shark
的前身,Shark
是 SparkSQL
的前身,SparkSQL
产生的根本原因是其完全脱离了 Hive
的限制。
SparkSQL
支持查询原生的RDD
。RDD
是Spark
平台的核心概念, 是Spark
能够高效的处理大数据的各种场景的基础。- 能够在
scala
、Java
中写SQL
语句。支持简单的SQL
语法检查,能够在Scala
中写Hive
语句访问Hive
数据,并将结果取回作为RDD
使用。
Spark on Hive
:Hive
只作为储存角色,Spark
负责sql
解析优化,执行。Hive on Spark
:Hive
即作为存储又负责sql
的解析优化,Spark
负责执行。两者数据源均为
Hive
表,底层人物均为Spark
人物,关键区别在于一个是Hive
去解析,一个是Spark
去解析。
name | 存数据的位置 | 解析引擎 | 执行引擎 |
---|---|---|---|
hive on spark | hive表 | hive | spark |
spark on hive | hive表 | spark | spark |
2.Dataset 与 DataFrame概念解析
Dataset
也是一个分布式数据容器。与 RDD
类似,然而 Dataset
更像传统数据库的二维表格,除了数据以外,还掌握数据的结构信息(元数据),即schema
。同时,与 Hive
类似,Dataset
也支持嵌套数据类型(struct、array 和 map)。从 API
易用性的角度上 看, Dataset API
提供的是一套高层的关系操作,比函数式的 RDD API
要更加友好,门槛更低。Dataset
的底层封装的是 RDD
,当 RDD
的泛型是 Row
类型的时候,我们也可以称它为 DataFrame
。
Dataset<Row> = DataFrame
3.SparkSQL 的数据源
SparkSQL
的数据源可以是 JSON
类型的字符串,JDBC
,Parquent
,Hive
,HDFS
等。
可以将不同源中的数据进行join
,这就是SparkSQL中的异构数据源的操作。
4.SparkSQL 底层架构
首先拿到 sql
后解析一批未被解决的逻辑计划,再经过分析得到分析后的逻辑计划,再经过一批优化规则转换成一批最佳优化的逻辑计划,再经过 SparkPlanner
的策略转化成一批物理计划,随后经过消费模型转换成一个个的 Spark
任务执行。
5.谓词下推(predicate Pushdown)
二、创建DataSet的几种方式
1.读取 json 格式的文件创建 Dataset
读取 json
格式的文件有两种方式:
- 一种是
spark.read.json(文件路径)
- 另一种是
spark.read.format("json").load(文件路径)
注意:
json
文件中的json
数据不能嵌套json
格式数据。Dataset
是一个一个Row
类型的RDD
,ds.rdd()/ds.javaRdd()
。df.show()
默认显示前 20 行数据。json
文件自带元数据,默认排序时字段名按照字典序排序,然后类型自动推断。- 注册成临时表时,表中的列默认按
ascii
顺序显示列。
package com.shsxt.scala_Test.sql.dataset
import org.apache.spark.sql.{
DataFrame, SQLContext, SparkSession}
object CreateDFFromJsonFile {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession
.builder()
.master("local")
.appName("jsonRDD")
.getOrCreate()
val jsonDS: DataFrame = spark.read.json("./data/json")
jsonDS.show();
jsonDS.createOrReplaceTempView("jsonTable")
val result: DataFrame = spark.sql("select * from jsonTable where age is not NULL")
result.show()
spark.stop()
}
}
+----+--------+
| age| name|
+----+--------+
| 18|zhangsan|
|null| lisi|
| 18| wangwu|
| 28| laoliu|
| 20|zhangsan|
|null| lisi|
| 18| wangwu|
| 28| laoliu|
| 28|zhangsan|
|null| lisi|
| 18| wangwu|
+----+--------+
+---+--------+
|age| name|
+---+--------+
| 18|zhangsan|
| 18| wangwu|
| 28| laoliu|
| 20|zhangsan|
| 18| wangwu|
| 28| laoliu|
| 28|zhangsan|
| 18| wangwu|
+---+--------+
2.通过 json 格式的 RDD 创建 Dataset
package com.shsxt.scala_Test.sql.dataset
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{
DataFrame, Dataset, SQLContext, SparkSession}
case class Person(id: String, name: String, age: Integer)
object CreateDFFromRDDWithReflect {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession
.builder()
.master("local")
.appName("jsonRDD")
.getOrCreate()
val sc: SparkContext = spark.sparkContext
val nameRDD: RDD[String] = sc.parallelize(Array(
"{'name':'zhangsan','age':\"18\"}",
"{\"name\":\"lisi\",\"age\":\"19\"}",
"{\"name\":\"wangwu\",\"age\":\"20\"}"))
val scoreRDD: RDD[String] = sc.parallelize(Array(
"{\"name\":\"zhangsan\",\"score\":\"100\"}",
"{\"name\":\"lisi\",\"score\":\"200\"}",
"{\"name\":\"wangwu\",\"score\":\"300\"}"
))
val name: DataFrame = spark.read.json(nameRDD)
val score: DataFrame = spark.read.json(scoreRDD)
//注册成临时表使用
name.createOrReplaceTempView("nameTable");
score.createOrReplaceTempView("scoreTable");
val result: DataFrame = spark.sql(
"""
|select nameTable.name,nameTable.age,scoreTable.score
|from nameTable join scoreTable
|on nameTable.name = scoreTable.name
|""".stripMargin)
result.show()
spark.stop()
}
}
+--------+---+-----+
| name|age|score|
+--------+---+-----+
| wangwu| 20| 300|
|zhangsan| 18| 100|
| lisi| 19| 200|
+--------+