sparkSQL入门和实践(scala)

spark sql

什么是spark sql?

Spark SQL 是 Spark 用来处理结构化数据的一个模块,它提供了 2 个编程抽象:DataFrame 和DataSet,并且作为分布式 SQL 查询引擎的作用

spark sql提供功能-通过SchemaRDD

  • 从各种结构化数据源中读取数据
  • 支持在spark程序内使用SQL语句进行数据查询
  • spark sql支持sql于常规python/scala/java代码高度整合

schemaRDD

spark sql特点

Spark SQL 的特点
1)易整合
2)统一的数据访问方式
3)兼容 Hive
4)标准的数据连接

什么是 DataFrame

与 RDD 类似,DataFrame 也是一个分布式数据容器。然而 DataFrame 更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即 schema。同时,与 Hive 类似,DataFrame 也支持嵌套数据类型(struct、array 和 map)。从 API 易用性的角度上看,DataFrame API 提供的是一套高层的关系操作,比函数式的 RDD API 要更加友好,门槛更低。

在这里插入图片描述
上图直观地体现了 DataFrame 和 RDD 的区别。左侧的 RDD[Person]虽然以 Person 为类型参数,但 Spark 框架本身不了解 Person 类的内部结构。而右侧的 DataFrame 却提供了详细的结构信息,使得 Spark SQL 可以清楚地知道该数据集中包含哪些列,每列的名称和类型各是什么。DataFrame 是为数据提供了 Schema 的视图。可以把它当做数据库中的一张表来对待,DataFrame也是懒执行的。性能上比 RDD 要高,主要原因:优化的执行计划:查询计划通过 Spark catalyst optimizer 进行优化.

什么是 DataSet

1)是 Dataframe API 的一个扩展,是 Spark 最新的数据抽象。
2)用户友好的 API 风格,既具有类型安全检查也具有 Dataframe 的查询优化特性。
3)Dataset 支持编解码器,当需要访问非堆上的数据时可以避免反序列化整个对象,提高了效率。
4)样例类被用来在 Dataset 中定义数据的结构信息,样例类中每个属性的名称直接映射到DataSet 中的字段名称。
5)Dataframe 是 Dataset 的特例,DataFrame=Dataset[Row] ,所以可以通过 as 方法将 Dataframe转换为 Dataset。Row 是一个类型,跟 Car、Person 这些的类型一样,所有的表结构信息都用 Row来表示。
6)DataSet 是强类型的。比如可以有 Dataset[Car],Dataset[Person].
7)DataFrame 只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候检查是否类型失败的,比如你可以对一个 String 进行减法操作,在执行的时候才报错,而 DataSet 不仅仅知道字段,而且知道字段类型,所以有更严格的错误检查。就跟 JSON 对象和类对象之间的类比。

SparkSQL编程

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

SparkSession 是 Spark 最新的 SQL 查询起始点,实质上是 SQLContext 和 HiveContext 的组合,所以在 SQLContext 和 HiveContext 上可用的 API 在
SparkSession 上同样是可以使用的。SparkSession 内部封装了 sparkContext,所以计算实际上是由 sparkContext 完成的。

DataFrame

创建

在 Spark SQL 中 SparkSession 是创建 DataFrame 和执行 SQL 的入口,创建 DataFrame 有三种方式:

  • 通过 Spark 的数据源进行创建;
  • 从一个存在的 RDD 进行转换;
  • 从 Hive Table 进行查询返回;

(1)从 Spark 数据源进行创建

读取 json 文件创建 DataFrame

val df = spark.read.json("***/people.json")
df.createOrReplaceTempView("people")
val sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show

结果如下:
在这里插入图片描述
(2)从一个存在的 RDD 进行转换;

注意:如果需要 RDD 与 DF 或者 DS 之间操作,那么都需要引入 import spark.implicits._ 【spark不是包名,而是 sparkSession 对象的名称】
前置条件:导入隐式转换并创建一个 RDD

import spark.implicits._
val peopleRDD = sc.textFile("***/people.txt")peopleRDD.map{x=>val para = x.split(",");(para(0),para(1).trim.toInt)}.toDF("name","age")
case class People(name:String, age:Int)
peopleRDD.map{ x => val para = x.split(",");People(para(0),para(1).trim.toInt)}.toDF

perple.txt内容如下:
在这里插入图片描述
执行效果:
在这里插入图片描述
dataframe常用方法:

  • 查看 DataFrame 的 Schema 信息 :df.printSchema
  • 只查看”col”列数据: df.select(" col").show()
  • 查看多列数据 df.select($“col”, $“col2” + 1).show()
  • 过滤 df.filter($“col” > 21).show()
  • 按照某列分组 df.groupBy(“col”).count().show()
DataFrame转换为RDD
val df = spark.read.json("***/people.json")
val dfToRDD = df.rdd

在这里插入图片描述

DataSet

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

创建

创建一个样例类,创建 DataSet

case class Person(name: String, age: Long)
val caseClassDS = Seq(Person("Andy", 32)).toDS()

在这里插入图片描述

RDD 转换为 DataSet

SparkSQL 能够自动将包含有 case 类的 RDD 转换成 DataFrame,case 类定义了 table 的结构,case 类属性通过反射变成了表的列名。Case 类可以包含诸如 Seqs 或者 Array 等复杂的结构

1)创建一个 RDD

val peopleRDD = sc.textFile("examples/src/main/resources/people.txt")

2)创建一个样例类

case class Person(name: String, age: Long)

3)将 RDD 转化为 DataSet

peopleRDD.map(line => {val para = line.split(",");Person(para(0),para(1).trim.toInt)}).toDS

在这里插入图片描述

DataFrame 与 DataSet 的互操作

DataFrame 转 Dataset
  1. 创建一个 DateFrame,
  2. 创建一个样例类
  3. 将 DateFrame 转化为 DataSet
val df = spark.read.json("**/people.json")
case class Person(name: String, age: Long)
df.as[Person]

在给出每一列的类型后,使用 as 方法,转成 Dataset,这在数据类型是 DataFrame 又需 要 针 对 各 个 字 段 处 理 时 很 方 便 。 在 使 用 一 些 特 殊 的 操 作 时 , 一 定 要 加 上 import spark.implicits._ 不然 toDF、toDS 无法使用。

Dataset 转 DataFrame

1)创建一个样例类

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

2)创建 DataSet

scala> val ds = Seq(Person("Andy", 32)).toDS()

3)将 DataSet 转化为 DataFrame

scala> val df = ds.toDF

RDD、DataFrame、DataSet

共性:

1、RDD、DataFrame、Dataset 全都是 spark 平台下的分布式弹性数据集,为处理超大型数据提供便利
2、三者都有惰性机制,在进行创建、转换,如 map 方法时,不会立即执行,只有在遇到 Action才会开始遍历运算。
3、三者都会根据 spark 的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存
溢出
4、三者都有 partition 的概念
5、三者有许多共同的函数,如 filter,排序等
6、在对 DataFrame 和 Dataset 进行操作许多操作都需要这个包进行支持import spark.implicits._
7、DataFrame 和 Dataset 均可使用模式匹配获取各个字段的值和类型

区别:
  1. RDD:
    1)RDD 一般和 spark mlib 同时使用
    2)RDD 不支持 sparksql 操作
  2. DataFrame:
    1)与 RDD 和 Dataset 不同,DataFrame 每一行的类型固定为 Row,每一列的值没法直接访问,只有通过解析才能获取各个字段的值,如:
testDF.foreach{
line =>
val col1=line.getAs[String]("col1")
val col2=line.getAs[String]("col2")
}

2)DataFrame 与 Dataset 一般不与 spark mllib 同时使用
3)DataFrame 与 Dataset 均支持 sparksql 的操作,比如 select,groupby 之类,还能注册临时表/视窗,进行 sql 语句操作,如:

dataDF.createOrReplaceTempView("tmp")
spark.sql("select ROW,DATE from tmp where DATE is not null order by 
DATE").show(100,false)

4)DataFrame 与 Dataset 支持一些特别方便的保存方式,比如保存成 csv,可以带上表头,这样每一列的字段名一目了然

//保存
val saveoptions = Map("header" -> "true", "delimiter" -> "\t", "path"
-> "hdfs://hadoop102:9000/test")
datawDF.write.format("spark.csv").mode(SaveMode.Overwrite
).options(saveoptions).save()
//读取
val options = Map("header" -> "true", "delimiter" -> "\t", "path" ->
"hdfs://hadoop102:9000/test")
val datarDF= spark.read.options(options).format("com.atguigu.spark.cs
v").load()

利用这样的保存方式,可以方便的获得字段名和列的对应,而且分隔符(delimiter)可以自由指定。
3. Dataset:
1)Dataset 和 DataFrame 拥有完全相同的成员函数,区别只是每一行的数据类型不同。
2)DataFrame 也可以叫 Dataset[Row],每一行的类型是 Row,不解析,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用上面提到的 getAS 方法或者共性中的第七条提到的模式匹配拿出特定字段。而 Dataset 中,每一行是什么类型是不一定的,在自定义了 case class之后可以很自由的获得每一行的信息

case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
/**
rdd
("a", 1)
("b", 1)
("a", 1)
**/
val test: Dataset[Coltest]=rdd.map{line=>
Coltest(line._1,line._2)
}.toDS
test.map{
line=>
println(line.col1)
println(line.col2)
}

可以看出,Dataset 在需要访问列中的某个字段时是非常方便的,然而,如果要写一些适配性很强的函数时,如果使用 Dataset,行的类型又不确定,可能是各种 case class,无法实现适配,这时候用 DataFrame 即 Dataset[Row]就能比较好的解决问题

参考: 尚硅谷2021迎新版大数据Spark从入门到精通视频对应课件内容

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值