SparkSQL核心编程

第1章 SparkSQL 概述

Spark SQL 是 Spark 用于结构化数据(structured data)处理的 Spark 模块。

➢ 数据兼容方面
SparkSQL 不但兼容 Hive,还可以从 RDD、parquet 文件、JSON 文件中获取数据,未来版本甚至支持获取 RDBMS 数据以及 cassandra 等 NOSQL 数据;

➢ 性能优化方面
除了采取 In-Memory Columnar Storage、byte-code generation 等优化技术外、将会引进 Cost Model 对查询进行动态评估、获取最佳物理计划等等;

➢ 组件扩展方面
无论是 SQL 的语法解析器、分析器还是优化器都可以重新定义,进行扩展。

SparkSQL 特点

易整合,统一的数据访问,兼容 Hive,标准数据连接

DataFrame

DataFrame 与 RDD 的主要区别在于,前者带有 schema 元信息,即 DataFrame所表示的二维表数据集的每一列都带有名称和类型.。

Spark SQL 的查询优化器会进行逻辑查询计划优化。它是一个利用基于关系代数的等价变换,将高成本的操作替换为低成本操作的过程。

DataSet

是分布式数据集合。是 DataFrame API 的一个扩展,是 SparkSQL 最新的数据抽象
DataFrame 是 DataSet 的特例,DataFrame=DataSet[Row] ,所以可以通过 as 方法将
DataFrame 转换为 DataSet。

第2章 SparkSQL 核心编程

2.1 新的起点

Spark Core 中,如果想要执行应用程序,需要首先构建上下文环境对象 SparkContext。
SparkSession 是 Spark 最新的 SQL 查询起始点,实质上是 SQLContext 和 HiveContext的组合,所以在 SQLContex 和 HiveContext 上可用的 API 在 SparkSession 上同样是可以使用的。SparkSession 内部封装了 SparkContext,所以计算实际上是由 sparkContext 完成的。当我们使用 spark-shell 的时候, spark 框架会自动的创建一个名称叫做 spark 的 SparkSession 对象, 就像我们以前可以自动获取到一个 sc 来表示 SparkContext 对象一样。

2.2 DataFrame

➢ 查看 Spark 支持创建文件的数据源格式

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

2.2.1 SQL 语法

  1. 读取 JSON 文件创建 DataFrame
scala> val df = spark.read.json("data/user.json") 
df: org.apache.spark.sql.DataFrame = [age: bigint, username: string] 
  1. 对 DataFrame 创建一个临时表
scala> df.createOrReplaceTempView("people") 
  1. 通过 SQL 语句实现查询全表
scala> val sqlDF = spark.sql("SELECT * FROM people") 
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string] 
  1. 结果展示
scala> sqlDF.show 
  1. 对于 DataFrame 创建一个全局表
scala> df.createGlobalTempView("people") 
  1. 通过 SQL 语句实现查询全表
scala> spark.sql("SELECT * FROM global_temp.people").show() 
or
scala> spark.newSession().sql("SELECT * FROM global_temp.people").show() 

2.2.2 DSL 语法

特定领域语言(domain-specific language, DSL)管理结构化的数据。

  1. 创建一个 DataFrame
scala> val df = spark.read.json("data/user.json") 
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string] 
  1. 查看 DataFrame 的 Schema 信息
scala> df.printSchema
  1. 只查看"username"列数据,
scala> df.select("username").show() 
  1. 查看"username"列数据以及"age+1"数据
    注意:涉及到运算的时候, 每列都必须使用$, 或者采用引号表达式:单引号+字段名
// 使用$版
scala> df.select($"username",$"age" + 1).show 
// 使用‘版
scala> df.select('username, 'age + 1).show() 
// 别名
scala> df.select('username, 'age + 1 as "newage").show() 
  1. 查看"age"大于"30"的数据
scala> df.filter($"age">30).show 
  1. 按照"age"分组,查看数据条数
scala> df.groupBy("age").count.show 

2.2.3 RDD,DataFrame 互转

RDD 转换为 DataFrame :.toDF

scala> val idRDD = sc.textFile("data/id.txt") 
scala> idRDD.toDF("id").show 

**DataFrame 转换为 RDD:.rdd **

// RDD转DataFrame 
scala> val df = sc.makeRDD(List(("zhangsan",30), ("lisi",40))).map(t=>User(t._1, t._2)).toDF 
df: org.apache.spark.sql.DataFrame = [name: string, age: int]
 
 // DataFrame转RDD
scala> val rdd = df.rdd 
rdd: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[46] at rdd at <console>:25 

2.3 DataSet

2.3.1 创建 DataSet

1) 使用样例类序列创建 DataSet

// 定义类Person
scala> case class Person(name: String, age: Long) 
// Person类序列toDS创建 DataSet 
scala> val caseClassDS = Seq(Person("zhangsan",2)).toDS() 

2) 使用基本类型的序列创建 DataSet

scala> val ds = Seq(1,2,3,4,5).toDS 

2.3.2 RDD、DataSet 互转

// 定义类User
scala> case class User(name:String, age:Int) 
// rdd转DataSet
scala> sc.makeRDD(List(("zhangsan",30), ("lisi",49))).map(t=>User(t._1, 
t._2)).toDS 
//DataSet转rdd
scala> val rdd = res11.rdd 

2.3.3 DataFrame 和 DataSet 互转

// 定义类User
scala> case class User(name:String, age:Int) 

scala> val df = sc.makeRDD(List(("zhangsan",30), 
("lisi",49))).toDF("name","age") 
 // DataFrame转DataSet
scala> val ds = df.as[User] 
 // DataSet 转 DataFrame 
scala> val df = ds.toDF

2.5 RDD、DataFrame、DataSet 三者的关系

——RDDDataFrameDataset
产生版本Spark1.0Spark1.3Spark1.6
区别一般和spark mllib同时使用,
不支持 sparksql 操作
一般不与 spark mllib 同时使用,
一行的类型固定为 Row,每一列的值没法直接访问,
与 DataSet 均支持 SparkSQL 的操作,
还能注册临时表/视窗,进行 sql 语句操作,
与 DataSet 支持一些特别方便的保存方式
是 DataSet 的一个特例,
也可以叫 Dataset[Row]
每一行的类型是 Row,
不解析

2.6 IDEA 开发 SparkSQL

2.6.1 添加依赖

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

2.6.2 代码实现

object SparkSQL01_Demo { 
  def main(args: Array[String]): Unit = { 
 // 1.创建上下文环境配置对象 
    val conf: SparkConf = new 
							SparkConf().setMaster("local[*]").setAppName("SparkSQL01_Demo") 
 
 // 2.创建 SparkSession 对象 
    val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate() 
    
 //RDD=>DataFrame=>DataSet 转换需要引入隐式转换规则,否则无法转换 
 //spark 不是包名,是上下文环境对象名 
    import spark.implicits._ 
 
 // json=>DataFrame 
 //读取 json 文件 创建 DataFrame {"username": "lisi","age": 18} 
    val df: DataFrame = spark.read.json("input/test.json") 
    //df.show() 
 
 //SQL 风格语法 
    df.createOrReplaceTempView("user") 
    //spark.sql("select avg(age) from user").show 
 
 //DSL 风格语法 
    //df.select("username","age").show() 
 
    //*****RDD=>DataFrame=>DataSet***** 
    //RDD 
    val rdd1: RDD[(Int, String, Int)] = 
				spark.sparkContext.makeRDD(List((1,"zhangsan",30),(2,"lisi",28),(3,"wangwu",
				20))) 
 
    //RDD=>DataFrame
    val df1: DataFrame = rdd1.toDF("id","name","age") 
    //df1.show() 
 
    //DataFrame=>DataSet
    val ds1: Dataset[User] = df1.as[User] 
    //ds1.show() 
 
    //*****DataSet=>DataFrame=>RDD***** 
    //DataSet=>DataFrame
    val df2: DataFrame = ds1.toDF() 
 
 //RDD 返回的 RDD 类型为 Row,里面提供的 getXXX 方法可以获取字段值,类似 jdbc 处理结果集,但是索引从 0 开始 
 	//DataFrame=>RDD
    val rdd2: RDD[Row] = df2.rdd 
    //rdd2.foreach(a=>println(a.getString(1))) 
 
    //*****RDD=>DataSet***** 
    rdd1.map{ 
         case (id,name,age)=>User(id,name,age) 
    }.toDS() 
 
    //*****DataSet=>=>RDD***** 
    ds1.rdd 
 
    //释放资源 
    spark.stop() 
  } 
} 
case class User(id:Int,name:String,age:Int) 

2.7 用户自定义函数

2.7.1 UDF

  1. 创建 DataFrame
scala> val df = spark.read.json("data/user.json") 
  1. 注册 UDF
scala> spark.udf.register("addName",(x:String)=> "Name:"+x) 
  1. 创建临时表
scala> df.createOrReplaceTempView("people") 
  1. 应用 UDF
scala> spark.sql("Select addName(name),age from people").show() 

2.7.2 UDAF

强类型的 Dataset 和弱类型的 DataFrame 都提供了相关的聚合函数, 如 count(),countDistinct(),avg(),max(),min()。

2.8 数据的加载和保存

2.8.1 通用的加载和保存方式

加载
spark.read.load 是加载数据的通用方法

scala> spark.read. 
csv   format   jdbc   json   load   option   options   orc   parquet   schema   
table   text   textFile 
//如果读取不同格式的数据,可以对不同的数据格式进行设定 
scala> spark.read.format("…")[.option("…")].load("…") 
//也可以直接在文件上进行查询: 文件格式.`文件路径` 
scala>spark.sql("select * from json.`/opt/module/data/user.json`").show 

保存数据
df.write.save 是保存数据的通用方法

scala>df.write. 
scala>df.write.format("…")[.option("…")].save("…") 

➢ format(“…”):指定保存的数据类型,包括"csv"、“jdbc”、“json”、“orc”、“parquet"和 “textFile”。
➢ save (”…“):在"csv”、“orc”、“parquet"和"textFile"格式下需要传入保存数据的路径。
➢ option(”…"):在"jdbc"格式下需要传入 JDBC 相应参数,url、user、password 和 dbtable 保存操作可以使用 SaveMode, 用来指明如何处理数据,使用 mode()方法来设置。

Scala/JavaAny LanguageMeaning
SaveMode.ErrorIfExists(default)“error”(default)如果文件已经存在则抛出异常
SaveMode.Append“append”如果文件已经存在则追加
SaveMode.Overwrite“overwrite”如果文件已经存在则覆盖
SaveMode.Ignore“ignore”如果文件已经存在则忽略

2.8.2 Parquet

  1. 加载数据
scala> val df = spark.read.load("examples/src/main/resources/users.parquet") 
scala> df.show 
  1. 保存数据
scala> var df = spark.read.json("/opt/module/data/input/people.json") 
//保存为 parquet 格式 
scala> df.write.mode("append").save("/opt/module/data/output") 

2.8.3 JSON

1)导入隐式转换 
import spark.implicits._ 
2)加载 JSON 文件 
val path = "/opt/module/spark-local/people.json" 
val peopleDF = spark.read.json(path) 
3)创建临时表 
peopleDF.createOrReplaceTempView("people") 
4)数据查询 
val teenagerNamesDF = spark.sql("SELECT name FROM people WHERE age BETWEEN 13 AND 19") 
teenagerNamesDF.show() 

2.8.4 CSV

spark.read.format("csv").option("sep", ";").option("inferSchema", "true").option("header", "true").load("data/user.csv") 

2.8.5 MySQL

1)导入依赖

<dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId> 
    <version>5.1.27</version> 
</dependency> 

2)读取数据

val conf: SparkConf = new 
SparkConf().setMaster("local[*]").setAppName("SparkSQL") 
 
//创建 SparkSession 对象 
val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate() 
 
import spark.implicits._ 
 
//方式 1:通用的 load 方法读取 
spark.read.format("jdbc") 
  .option("url", "jdbc:mysql://linux1:3306/spark-sql") 
  .option("driver", "com.mysql.jdbc.Driver") 
    .option("user", "root") 
  .option("password", "123123") 
  .option("dbtable", "user") 
  .load().show 
 
 
//方式 2:通用的 load 方法读取 参数另一种形式 
spark.read.format("jdbc") 
  .options(Map("url"->"jdbc:mysql://linux1:3306/spark-sql?user=root&password=
123123", 
    "dbtable"->"user","driver"->"com.mysql.jdbc.Driver")).load().show 
 
//方式 3:使用 jdbc 方法读取 
val props: Properties = new Properties() 
props.setProperty("user", "root") 
props.setProperty("password", "123123") 
val df: DataFrame = spark.read.jdbc("jdbc:mysql://linux1:3306/spark-sql", 
"user", props) 
df.show 
 
//释放资源 
spark.stop() 

3)写入数据

case class User2(name: String, age: Long) 
。。。 
val conf: SparkConf = new 
SparkConf().setMaster("local[*]").setAppName("SparkSQL") 
 
//创建 SparkSession 对象 
val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate() 
import spark.implicits._ 
 
val rdd: RDD[User2] = spark.sparkContext.makeRDD(List(User2("lisi", 20), 
User2("zs", 30))) 
val ds: Dataset[User2] = rdd.toDS 
//方式 1:通用的方式 format 指定写出类型 
ds.write 
  .format("jdbc") 
  .option("url", "jdbc:mysql://linux1:3306/spark-sql") 
  .option("user", "root") 
  .option("password", "123123") 
  .option("dbtable", "user") 
  .mode(SaveMode.Append) 
  .save() 
 
//方式 2:通过 jdbc 方法 
val props: Properties = new Properties() 
props.setProperty("user", "root") 
props.setProperty("password", "123123") 
ds.write.mode(SaveMode.Append).jdbc("jdbc:mysql://linux1:3306/spark-sql", 
"user", props) 
 
//释放资源 
spark.stop() 

2.8.6 Hive

代码操作 Hive
1)导入依赖

<dependency> 
    <groupId>org.apache.spark</groupId> 
    <artifactId>spark-hive_2.12</artifactId> 
    <version>3.0.0</version> 
</dependency> 
 
<dependency> 
    <groupId>org.apache.hive</groupId> 
    <artifactId>hive-exec</artifactId> 
    <version>1.2.1</version> 
</dependency> 
<dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId> 
    <version>5.1.27</version> 
</dependency> 

2)将 hive-site.xml 文件拷贝到项目的 resources 目录中,代码实现

//创建 SparkSession 
val spark: SparkSession = SparkSession 
  .builder() 
  .enableHiveSupport() 
  .master("local[*]") 
  .appName("sql") 
  .getOrCreate() 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值