spark3.0版本--SparkSQL

spark3.0版本--SparkSQL

  • 第1章 Spark SQL概述
    • 1.1 什么是Spark SQL
    • 1.2 为什么要有Spark SQL
    • 1.3 Spark SQL原理
      • 1.3.1 什么是DataFrame
      • 1.3.2 什么是DataSet
      • 1.3.3 RDD、DataFrame和DataSet之间关系
    • 1.4 Spark SQL的特点
  • 第2章 Spark SQL编程
    • 2.1 SparkSession新的起始点
    • 2.2 DataFrame
      • 2.2.1 创建DataFrame
      • 2.2.3 DSL风格语法
    • 2.3 DataSet
      • 2.3.1 创建DataSet(基本类型序列)
      • 2.3.2 创建DataSet(样例类序列)
    • 2.4 RDD、DataFrame、DataSet相互转换
      • 2.4.1 IDEA创建SparkSQL工程
      • 2.4.2 RDD与DataFrame相互转换
      • 2.4.3 RDD与DataSet相互转换
      • 2.4.4 DataFrame与DataSet相互转换
    • 2.5 用户自定义函数
      • 2.5.1 UDF
      • 2.5.2 UDAF
      • 2.5.3 UDTF(没有)
  • 第3章 SparkSQL数据的加载与保存
    • 3.1 加载数据
    • 3.2 保存数据
    • 3.3 与MySQL交互
    • 3.4 与Hive交互
      • 3.4.1 内嵌Hive应用
      • 3.4.2 外部Hive应用
      • 3.4.3 运行Spark SQL CLI
      • 3.4.4 IDEA操作外部Hive
  • 第4章 SparkSQL项目实战
    • 4.1 准备数据
    • 4.2 需求:各区域==热门==商品Top3
      • 4.2.1 需求简介
      • 4.2.3 代码实现

大数据技术之SparkSQL
版本:V3.0–spark

第1章 Spark SQL概述

1.1 什么是Spark SQL

spark3.0版本--SparkSQL_第1张图片

1.2 为什么要有Spark SQL

spark3.0版本--SparkSQL_第2张图片

1.3 Spark SQL原理

spark3.0版本--SparkSQL_第3张图片

1.3.1 什么是DataFrame

1)DataFrame是一种类似RDD的分布式数据集,类似于传统数据库中的二维表格。
2)DataFrame与RDD的主要区别在于,DataFrame带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。
spark3.0版本--SparkSQL_第4张图片

左侧的RDD[Person]虽然以Person为类型参数,但Spark框架本身不了解Person类的内部结构。而右侧的DataFrame却提供了详细的结构信息,使得Spark SQL可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。
3)Spark SQL性能上比RDD要高。因为Spark SQL了解数据内部结构,从而对藏于DataFrame背后的数据源以及作用于DataFrame之上的变换进行了针对性的优化,最终达到大幅提升运行时效率的目标。反观RDD,由于无从得知所存数据元素的具体内部结构,Spark Core只能在Stage层面进行简单、通用的流水线优化。
spark3.0版本--SparkSQL_第5张图片
spark3.0版本--SparkSQL_第6张图片

1.3.2 什么是DataSet

1.DataSet是分布式数据集合。
2.删除线格式 DataSet是强类型的。比如可以有DataSet[Car],DataSet[User]。具有类型安全检查
3.DataFrame是DataSet的特例,type DataFrame = DataSet[Row] ,Row是一个类型,跟Car、User这些的类型一样,所有的表结构信息都用Row来表示。

1.3.3 RDD、DataFrame和DataSet之间关系

1)发展历史
RDD(Spark1.0)=》Dataframe(Spark1.3)=》Dataset(Spark1.6)
如果同样的数据都给到这三个数据结构,他们分别计算之后,都会给出相同的结果。不同的是他们的执行效率和执行方式。在后期的Spark版本中,DataSet有可能会逐步取代RDD和DataFrame成为唯一的API接口
2)三者的共性
(1)RDD、DataFrame、DataSet全都是Spark平台下的分布式弹性数据集,为处理超大型数据提供便利
(2)三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action行动算子如foreach时,三者才会开始遍历运算
(3)三者有许多共同的函数,如filter,排序等
(4)三者都会根据Spark的内存情况自动缓存运算
(5)三者都有分区的概念

1.4 Spark SQL的特点

1)易整合
无缝的整合了SQL查询和Spark编程。
spark3.0版本--SparkSQL_第7张图片

2)统一的数据访问方式
使用相同的方式连接不同的数据源。
spark3.0版本--SparkSQL_第8张图片

3)兼容Hive
在已有的仓库上直接运行SQL或者HQL。
spark3.0版本--SparkSQL_第9张图片

4)标准的数据连接
通过JDBC或者ODBC来连接
spark3.0版本--SparkSQL_第10张图片

第2章 Spark SQL编程

本章重点学习如何使用DataFrame和DataSet进行编程,以及他们之间的关系和转换,关于具体的SQL书写不是本章的重点。

2.1 SparkSession新的起始点

在老的版本中,SparkSQL提供两种SQL查询起始点:
1.一个叫SQLContext,用于Spark自己提供的SQL查询;
2.一个叫HiveContext,用于连接Hive的查询。

SparkSession是Spark最新的SQL查询起始点,实质上是SQLContext和HiveContext的组合,所以在SQLContext和HiveContext上可用的API在SparkSession上同样是可以使用的。

SparkSession内部封装了SparkContext,所以计算实际上是由SparkContext完成的。当我们使用spark-shell的时候,Spark框架会自动的创建一个名称叫做Spark的SparkSession,就像我们以前可以自动获取到一个sc来表示SparkContext。

[atguigu@hadoop102 spark-local]$ bin/spark-shell

20/09/12 11:16:35 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
Spark context Web UI available at http://hadoop102:4040
Spark context available as 'sc' (master = local[*], app id = local-1599880621394).
Spark session available as 'spark'.
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /___/ .__/\_,_/_/ /_/\_\   version 3.0.0
      /_/
         
Using Scala version 2.12.10 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_212)
Type in expressions to have them evaluated.
Type :help for more information.

2.2 DataFrame

DataFrame是一种类似于RDD为基础的分布式数据集,类似于传统数据库中的二维表格。

2.2.1 创建DataFrame

在Spark SQL中SparkSession是创建DataFrame和执行SQL的入口,创建DataFrame有三种方式:
1.通过Spark的数据源进行创建;
2.从一个存在的RDD进行转换;
3. 还可以从Hive Table进行查询返回。
1)从Spark数据源进行创建
(1)数据准备,在/opt/module/spark-local目录下创建一个user.json文件

{
   "age":20,"name":"qiaofeng"}
{
   "age":19,"name":"xuzhu"}
{
   "age":18,"name":"duanyu"}

(2)查看Spark支持创建文件的数据源格式,使用tab键查看

scala> spark.read.
csv   format   jdbc   json   load   option   options   orc   parquet   schema   table   text   textFile

(3)读取json文件创建DataFrame
scala> val df = spark.read.json("/opt/module/spark-local/user.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
注意:如果从内存中获取数据,Spark可以知道数据类型具体是什么,如果是数字,默认作为Int处理;但是从文件中读取的数字,不能确定是什么类型,所以用BigInt接收,可以和Long类型转换,但是和Int不能进行转换。
(4)查看DataFrame算子

scala> df.

(5)展示结果

scala> df.show
+---+--------+
|age|    name|
+---+--------+
| 20|qiaofeng|
| 19|   xuzhu|
| 18|  duanyu|
+---+--------+

2)从RDD进行转换
2.4节我们专门讨论
3)Hive Table进行查询返回
3.4节我们专门讨论
2.2.2 SQL风格语法
SQL语法风格是指我们查询数据的时候使用SQL语句来查询,这种风格的查询必须要有临时视图或者全局视图来辅助。
视图:对特定表的数据的查询结果重复使用。View只能查询,不能修改和插入。
select * from t_user where age > 30 的查询结果可以存储在临时表(视图)v_user_age中,方便在后面重复使用。例如:select * from v_user_age
1)临时视图
(1)创建一个DataFrame

scala> val df = spark.read.json("/opt/module/spark-local/user.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

(2)对DataFrame创建一个临时视图

scala> df.createOrReplaceTempView("user")

createOrReplaceTempView

(3)通过SQL语句实现查询全表

scala> val sqlDF = spark.sql("SELECT * FROM user")
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

SELECT * FROM user

(4)结果展示

scala> sqlDF.show
+---+--------+
|age|    name|
+---+--------+
| 20|qiaofeng|
| 19|   xuzhu|
| 18|  duanyu|
+---+--------+

(5)求年龄的平均值

scala> val sqlDF = spark.sql("SELECT avg(age) from user")
sqlDF: org.apache.spark.sql.DataFrame = [avg(age): double]

SELECT avg(age) from user

(6)结果展示

scala> sqlDF.show
+--------+                                                                      
|avg(age)|
+--------+
|    19.0|
+--------+

(7)创建一个新会话再执行,发现视图找不到

scala> spark.newSession().sql("SELECT avg(age) from user ").show()
org.apache.spark.sql.AnalysisException: Table or view not found: user; line 1 pos 14;

spark.newSession().sql("SELECT avg(age) from user ").show()
org.apache.spark.sql.AnalysisException: Table or view not found: user; line 1 pos 14;

注意:普通临时视图是Session范围内的,如果想全局有效,可以创建全局临时视图。
2)全局视图
(1)对于DataFrame创建一个全局视图

scala> df.createOrReplaceGlobalTempView ("user2")

createOrReplaceGlobalTempView

(2)通过SQL语句实现查询全表

scala> spark.sql("SELECT * FROM global_temp.user2").show()
+---+--------+
|age|    name|
+---+--------+
| 20|qiaofeng|
| 19|   xuzhu|
| 18|  duanyu|
+---+--------+

global_temp

(3)新建session,通过SQL语句实现查询全表

scala> spark.newSession().sql("SELECT * FROM global_temp.user2").show()
+---+--------+
|age|    name|
+---+--------+
| 20|qiaofeng|
| 19|   xuzhu|
| 18|  duanyu|
+---+--------+

newSession()
global_temp

2.2.3 DSL风格语法

DataFrame提供一个特定领域语言(domain-specific language,DSL)去管理结构化的数据,可以在Scala,Java,Python和R中使用DSL,使用DSL语法风格不必去创建临时视图了
1)创建一个DataFrame

scala> val df = spark.read.json("/opt/module/spark-local/user.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

2)查看DataFrame的Schema信息

scala> df.printSchema
root
 |-- age: Long (nullable = true)
 |-- name: string (nullable = true)

3)只查看“name”列数据
==注意:列名要用双引号引起来,如果是单引号的话,只能在前面加一个单引号。=

scala> df.select("name").show()
+--------+
|  name|
+--------+
|qiaofeng|
|  xuzhu|
| duanyu|
+--------+
scala> df.select('name).show
+--------+
|  name|
+--------+
|qiaofeng|
|  xuzhu|
| duanyu|
+--------+

4)查看年龄和姓名,且年龄大于18

scala> df.select("age","name").where("age>18").show
+---+--------+
|age|  name|
+---+--------+
| 20|qiaofeng|
| 19|  xuzhu|
+---+--------+

5)查看所有列

scala> df.select("*").show
+---+--------+
|age|  name|
+---+--------+
| 20| qiaofeng|
| 19|   xuzhu|
| 18|  duanyu|
+---+--------+

6)查看“name”列数据以及“age+1”数据
注意:涉及到运算的时候,每列都必须使用$,或者采用单引号表达式:单引号+字段名

scala> df.select($"name",$"age" + 1).show
scala> df.select('name, 'age + 1).show()
scala> df.select('name, 'age + 1 as "newage").show()

+--------+---------+
| name  |(age + 1)|
+--------+---------+
|qiaofeng|    21|
|  xuzhu|    20|
| duanyu|    19|
+--------+---------+

7)查看“age”大于“19”的数据

scala> df.filter("age>19").show
+---+--------+
|age |  name|
+---+--------+
| 20|qiaofeng|
+---+--------+

8)按照“age”分组,查看数据条数

scala> df.groupBy("age").count.show
+---+-----+
|age|count|
+---+-----+
| 19|    1|
| 18|    1|
| 20|    1|
+---+-----+

9)求平均年龄avg(age)

scala> df.agg(avg("age")).show
+--------+
|avg(age)|
+--------+
|   19.0|
+--------+

10)求年龄总和sum(age)

scala> df.agg(max("age")).show
+--------+
|max(age)|
+--------+
|     20|
+--------+

df.agg ,agg类似于于RRD中aggregateRDD

2.3 DataSet

DataSet是具有强类型的数据集合,需要提供对应的类型信息。

2.3.1 创建DataSet(基本类型序列)

使用基本类型的序列创建DataSet
(1)将集合转换为DataSet

scala> val ds = Seq(1,2,3,4,5,6).toDS
ds: org.apache.spark.sql.Dataset[Int] = [value: int]

(2)查看DataSet的值

scala> ds.show
+-----+
|value|
+-----+
|    1|
|    2|
|    3|
|    4|
|    5|
|    6|
+-----+

2.3.2 创建DataSet(样例类序列)

使用样例类序列创建DataSet
(1)创建一个User的样例类

scala> case class User(name: String, age: Long)
defined class User

(2)将集合转换为DataSet

scala> val caseClassDS = Seq(User("wangyuyan",18)).toDS()
caseClassDS: org.apache.spark.sql.Dataset[User] = [name: string, age: bigint]

(3)查看DataSet的值

scala> caseClassDS.show
+---------+---+
|     name|age|
+---------+---+
|wangyuyan|  18|
+---------+---+

注意:在实际开发的时候,很少会把序列转换成DataSet,更多是通过RDD和DataFrame转换来得到DataSet

2.4 RDD、DataFrame、DataSet相互转换

spark3.0版本--SparkSQL_第11张图片

2.4.1 IDEA创建SparkSQL工程

1)创建一个maven工程SparkSQLTest
2)在项目SparkSQLTest上点击右键,Add Framework Support=》勾选scala
3)在main下创建scala文件夹,并右键Mark Directory as Sources Root=>在scala下创建包名为com.atguigu.sparksql
4)输入文件夹准备:在新建的SparkSQLTest项目名称上右键=》新建input文件夹=》在input文件夹上右键=》新建user.json。并输入如下内容:

{
   "age":20,"name":"qiaofeng"}
{
   "age":19,"name":"xuzhu"}
{
   "age":18,"name":"duanyu"}

5)在pom.xml文件中添加spark-sql的依赖和scala的编译插件

<dependencies>
    <dependency>
        <groupId>org.apache.sparkgroupId>
        <artifactId>spark-sql_2.12artifactId>
        <version>3.0.0version>
    dependency

你可能感兴趣的:(大数据,spark3.0,大数据,spark)