【Spark】Day03-Spark SQL:DataFrame、DataSet、sql编程与转换、项目实战(区域热门商品)
一、概述
1、介绍
将Spark SQL转换成RDD,然后提交到集群执行【对比hive】
提供2个编程抽象:DataFrame&DataSet
可以使用SQL和DatasetAPI与Spark SQL交互
2、特点
易整合SQL和spark
统一的数据访问方式
兼容hive,可以直接运行SQL或hql
标准数据连接JDBC/ODBC
3、DataFrame
以RDD为基础,每一列都带有名称和类型
支持嵌套数据类型(struct、array和map)
懒执行,但通过查询计划优化(先过滤后join)【基于关系代数的等价变换】,能获得高性能
4、DataSet
分布式数据库集合
DataFrame=DataSet[Row]
二、Spark SQL编程
1、SparkSession查询起始点
老版本有两种:SQLContext 和 HiveContext
SparkSession是Spark最新的SQL查询起始点
SparkSession内部封装了sparkContext,实际上是由sparkContext完成计算
2、DataFrame
【转换重要,DataSet的API更具有函数式】
(1)创建DataFrame
数据源、json、其他RDD转换【spark.read.xxx】
(2)SQL风格语法
创建临时表df.createOrReplaceTempView("people") --session范围内有效
整体范围内有效需要创建全局表:df.createGlobalTempView("people")
SQL查询并显示:
val sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show
(3)特定领域语言(domain-specific language, DSL)DSL风格语法
查看DataFrame的Schema信息:df.printSchema
查看某一列或所有列:
df.select("name").show()
df.select("*").show
df.select($"name",$"age" + 1).show --涉及运算,列名用$
df.filter($"age">19).show
df.groupBy("age").count.show
(4)RDD转换为DataFrame
需要引入 import spark(sparkSession对象).implicits._
手动转换
peopleRDD.map{x=> val fields=x.split(",");(fields(0),fields(1).trim.toInt)}.toDF("name","age").show
样例类反射转换
//创建样例类
case class People(name:String,age:Int)
//根据样例类转换
peopleRDD.map{x=> var fields=x.split(",");People(fields(0),fields(1).toInt)}.toDF.show
编程方式转换
package day05 import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession} object DataFrameDemo2 {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder()
.master("local[*]")
.appName("Word Count")
.getOrCreate()
val sc: SparkContext = spark.sparkContext
val rdd: RDD[(String, Int)] = sc.parallelize(Array(("lisi", 10), ("zs", 20), ("zhiling", 40)))
// 映射出来一个 RDD[Row], 因为 DataFrame其实就是 DataSet[Row]
val rowRdd: RDD[Row] = rdd.map(x => Row(x._1, x._2))
// 创建 StructType 类型
val types = StructType(Array(StructField("name", StringType), StructField("age", IntegerType)))
val df: DataFrame = spark.createDataFrame(rowRdd, types)
df.show
}
}
(5)DataFrame转换为RDD
val df = spark.read.json("/opt/module/spark-local/people.json")
直接调用rdd:val dfToRDD = df.rdd
打印RDD:dfToRDD.collect
3、DataSet
(1)创建DataSet
使用样例类序列创建DataSet
//创建样例类
case class Person(name: String, age: Long)
//构造样例类序列
val caseClassDS = Seq(Person("wangyuyan",2)).toDS()
//查看详细信息
caseClassDS.show
使用基本类型的序列创建DataSet
val ds = Seq(1,2,3,4,5,6).toDS
注意:不常通过序列,多用RDD转换
(2)RDD转换为DataSet
//创建RDD
val peopleRDD = sc.textFile("/opt/module/spark-local/people.txt")
//创建样例类
case class Person(name:String,age:Int)
//将RDD转化为DataSet
peopleRDD.map(line => {val fields = line.split(",");Person(fields(0),fields(1). toInt)}).toDS
(3)DataSet转换为RDD
//创建DataSet
val DS = Seq(Person("zhangcuishan", 32)).toDS()
//将DataSet转换为RDD
DS.rdd
4、DataFrame与DataSet的互操作
(1)DataFrame转为DataSet
import spark.implicits._
//创建一个DateFrame
val df = spark.read.json("/opt/module/spark-local/people.json")
//创建一个样例类
case class Person(name: String,age: Long)
//将DataFrame转化为DataSet
df.as[Person]
(2)Dataset转为DataFrame
//创建一个样例类
case class Person(name: String,age: Long)
//创建DataSet
val ds = Seq(Person("zhangwuji",32)).toDS()
//将DataSet转化为DataFrame
var df = ds.toDF
//展示
df.show
5、RDD、DataFrame和DataSet之间的关系
(1)共性
都是spark平台下的分布式弹性数据集
都有惰性机制,遇到action算子才执行计算
自动缓存,避免溢出
都有partition的概念
可使用模式匹配获取各个字段的值和类型
(2)区别
行类型不同
应用场景
(3)相互转换
6、IDEA创建SparkSQL程序
object SparkSQL01_Demo {
def main(args: Array[String]): Unit = {
//创建上下文环境配置对象
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSQL01_Demo") //创建SparkSession对象
val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate()
//RDD=>DataFrame=>DataSet转换需要引入隐式转换规则,否则无法转换
//spark不是包名,是上下文环境对象名
import spark.implicits._ //读取json文件 创建DataFrame {"username": "lisi","age": 18}
val df: DataFrame = spark.read.json("D:\\dev\\workspace\\spark-bak\\spark-bak-00\\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,"qiaofeng",30),(2,"xuzhu",28),(3,"duanyu",20))) //DataFrame
val df1: DataFrame = rdd1.toDF("id","name","age")
//df1.show() //DateSet
val ds1: Dataset[User] = df1.as[User]
//ds1.show() //*****DataSet=>DataFrame=>RDD*****
//DataFrame
val df2: DataFrame = ds1.toDF() //RDD 返回的RDD类型为Row,里面提供的getXXX方法可以获取字段值,类似jdbc处理结果集,但是索引从0开始
val rdd2: RDD[Row] = df2.rdd
//rdd2.foreach(a=>println(a.getString(1))) //*****RDD=>DataSe*****
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)
7、用户自定义函数
(1)UDF:输入一行,返回一个结果
//创建DataFrame
val df = spark.read.json("/opt/module/spark-local/people.json")
//打印数据
df.show
//注册UDF,功能为在数据前添加字符串
spark.udf.register("addName",(x:String)=> "Name:"+x)
//创建临时表
df.createOrReplaceTempView("people")
//应用UDF
spark.sql("Select addName(name),age from people").show()
(2)UDAF(User Defined Aggregate Function):输入多行,返回一行【用户自定义聚合函数】
需求:实现求平均年龄
RDD算子方式实现
val res: (Int, Int) = sc.makeRDD(List(("zhangsan", 20), ("lisi", 30), ("wangw", 40))).map {
case (name, age) => {
(age, 1)
}
}.reduce {
(t1, t2) => {
(t1._1 + t2._1, t1._2 + t2._2)
}
}
println(res._1/res._2)
自定义累加器方式实现(减少shuffle提高效率)
var sumAc = new MyAC
sc.register(sumAc)
sc.makeRDD(List(("zhangsan",20),("lisi",30),("wangw",40))).foreach{
case (name,age)=>{
sumAc.add(age)
}
}
println(sumAc.value) class MyAC extends AccumulatorV2[Int,Int]{
内部包含copy、reset、add、merge函数
自定义聚合函数实现-弱类型
//在spark中注册聚合函数
spark.udf.register("avgAge",myAverage) //读取数据 {"username": "zhangsan","age": 20}
val df: DataFrame = spark.read.json("D:\\dev\\workspace\\spark-bak\\spark-bak-00\\input\\test.json") //创建临时视图
df.createOrReplaceTempView("user") //使用自定义函数查询
spark.sql("select avgAge(age) from user").show()
自定义聚合函数实现-强类型
(3)UDTF:输入一行,返回多行
spark用flatMap即可实现该功能
三、SparkSQL数据的加载与保存
1、通用的加载和保存方式
(1)加载数据
spark.read.直接加载
format加载指定数据类型:spark.read.format("json").load ("/opt/module/spark-local/people.json").show
文件上直接进行查询(反引号):spark.sql("select * from json.`/opt/module/spark-local/people.json`").show
(2)保存数据
write直接保存数据
format指定保存数据类型:df.write.mode("append/覆盖/忽略").json("/opt/module/spark-local/output")
(3)默认数据源:Parquet列式存储
配置项spark.sql.sources.default,可修改默认数据源格式
2、JSON文件
spark SQL能自动推测 JSON数据集的结构,并将它加载为一个Dataset[Row].
peopleDF.createOrReplaceTempView("people")
val teenagerNamesDF = spark.sql("SELECT name FROM people WHERE age BETWEEN 13 AND 19")
teenagerNamesDF.show()
3、MySQL
可以通过JDBC读写数据,使用spark-shell操作需要指定jar包路径
可以使用通用的load方法或者jdbc方法
(1)从JDBC读数据
//方式2:通用的load方法读取 参数另一种形式
spark.read.format("jdbc")
.options(Map("url"->"jdbc:mysql://hadoop202:3306/test?user=root&password=123456",
"dbtable"->"user","driver"->"com.mysql.jdbc.Driver")).load().show //方式3:使用jdbc方法读取
val props: Properties = new Properties()
props.setProperty("user", "root")
props.setProperty("password", "123456")
val df: DataFrame = spark.read.jdbc("jdbc:mysql://hadoop202:3306/test", "user", props)
df.show
(2)向JDBC写数据
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://hadoop202:3306/test")
.option("user", "root")
.option("password", "123456")
.option("dbtable", "user")
.mode(SaveMode.Append)
.save() //方式2:通过jdbc方法
val props: Properties = new Properties()
props.setProperty("user", "root")
props.setProperty("password", "123456")
ds.write.mode(SaveMode.Append).jdbc("jdbc:mysql://hadoop202:3306/test", "user", props)
4、Hive
Spark SQL编译时可以包含 Hive 支持,也可以不包含
(1)使用内嵌hive
直接使用即可
spark.sql("show tables").show
spark.sql("create table aa(id int)")
spark.sql("show tables").show
//向表中加载数据
spark.sql("load data local inpath './ids.txt' into table aa")
(2)外部hive应用
步骤:拷贝驱动和配置文件、提前启动hive
能够查到外部hive的大量表
(3)运行Spark SQL CLI
本地运行Hive元数据服务以及从命令行执行查询任务
执行bin/spark-sql
(4)代码中操作Hive
object SparkSQL08_Hive{
def main(args: Array[String]): Unit = {
//创建上下文环境配置对象
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSQL01_Demo")
val spark: SparkSession = SparkSession
.builder()
.enableHiveSupport()
.master("local[*]")
.appName("SQLTest")
.getOrCreate()
spark.sql("show tables").show()
//释放资源
spark.stop()
}
}
四、SparkSQL项目实战
1、准备数据
hive中创建3张表: 1张用户行为表,1张城市表,1 张产品表
2、需求:各区域热门商品Top3
(1)需求简介
计算各个区域前三大热门商品,并备注上每个商品在主要城市中的分布比例,超过两个城市用其他显示
地区 |
商品名称 |
点击次数 |
城市备注 |
华北 |
商品A |
100000 |
北京21.2%,天津13.2%,其他65.6% |
华北 |
商品P |
80200 |
北京63.0%,太原10%,其他27.0% |
华北 |
商品M |
40000 |
北京63.0%,太原10%,其他27.0% |
东北 |
商品J |
92000 |
大连28%,辽宁17.0%,其他 55.0% |
(2)思路分析
查询出来所有的点击记录,并与 city_info 表连接,得到每个城市所在的地区,与 Product_info 表连接得到产品名称
按照地区和商品名称分组,统计出每个商品在每个地区的总点击次数
按照点击次数降序排列
城市备注需要自定义 UDAF 函数
(3)代码实现
val spark: SparkSession = SparkSession
.builder()
.master("local[2]")
.appName("AreaClickApp")
.enableHiveSupport()
.getOrCreate()
spark.sql("use sparkpractice")
// 0 注册自定义聚合函数
spark.udf.register("city_remark", new AreaClickUDAF)
// 1. 查询出所有的点击记录,并和城市表产品表做内连接
spark.sql(
"""
|select
| c.*,
| v.click_product_id,
| p.product_name
|from user_visit_action v join city_info c join product_info p on v.city_id=c.city_id and v.click_product_id=p.product_id
|where click_product_id>-1
""".stripMargin).createOrReplaceTempView("t1") // 2. 计算每个区域, 每个产品的点击量
spark.sql(
"""
|select
| t1.area,
| t1.product_name,
| count(*) click_count,
| city_remark(t1.city_name)
|from t1
|group by t1.area, t1.product_name
""".stripMargin).createOrReplaceTempView("t2") // 3. 对每个区域内产品的点击量进行倒序排列
spark.sql(
"""
|select
| *,
| rank() over(partition by t2.area order by t2.click_count desc) rank
|from t2
""".stripMargin).createOrReplaceTempView("t3") // 4. 每个区域取top3 spark.sql(
"""
|select
| *
|from t3
|where rank<=3
""".stripMargin).show //释放资源
spark.stop()
【Spark】Day03-Spark SQL:DataFrame、DataSet、sql编程与转换、项目实战(区域热门商品)的更多相关文章
- spark的数据结构 RDD——DataFrame——DataSet区别
转载自:http://blog.csdn.net/wo334499/article/details/51689549 RDD 优点: 编译时类型安全 编译时就能检查出类型错误 面向对象的编程风格 直接 ...
- Spark大型项目实战:电商用户行为分析大数据平台
本项目主要讲解了一套应用于互联网电商企业中,使用Java.Spark等技术开发的大数据统计分析平台,对电商网站的各种用户行为(访问行为.页面跳转行为.购物行为.广告点击行为等)进行复杂的分析.用统计分 ...
- RDD、DataFrame、Dataset三者三者之间转换
转化: RDD.DataFrame.Dataset三者有许多共性,有各自适用的场景常常需要在三者之间转换 DataFrame/Dataset转RDD: 这个转换很简单 val rdd1=testDF. ...
- spark第七篇:Spark SQL, DataFrame and Dataset Guide
预览 Spark SQL是用来处理结构化数据的Spark模块.有几种与Spark SQL进行交互的方式,包括SQL和Dataset API. 本指南中的所有例子都可以在spark-shell,pysp ...
- APACHE SPARK 2.0 API IMPROVEMENTS: RDD, DATAFRAME, DATASET AND SQL
What’s New, What’s Changed and How to get Started. Are you ready for Apache Spark 2.0? If you are ju ...
- Spark SQL - DataFrame
1 Overview Spark SQL is a Spark module for structured data processing. It provides a programming abs ...
- 大数据技术之_27_电商平台数据分析项目_02_预备知识 + Scala + Spark Core + Spark SQL + Spark Streaming + Java 对象池
第0章 预备知识0.1 Scala0.1.1 Scala 操作符0.1.2 拉链操作0.2 Spark Core0.2.1 Spark RDD 持久化0.2.2 Spark 共享变量0.3 Spark ...
- Spark入门之DataFrame/DataSet
目录 Part I. Gentle Overview of Big Data and Spark Overview 1.基本架构 2.基本概念 3.例子(可跳过) Spark工具箱 1.Dataset ...
- [Spark] 05 - Spark SQL
关于Spark SQL,首先会想到一个问题:Apache Hive vs Apache Spark SQL – 13 Amazing Differences Hive has been known t ...
- 59、Spark Streaming与Spark SQL结合使用之top3热门商品实时统计案例
一.top3热门商品实时统计案例 1.概述 Spark Streaming最强大的地方在于,可以与Spark Core.Spark SQL整合使用,之前已经通过transform.foreachRDD ...
随机推荐
- Elasitcsearch7.X集群/索引备份与恢复实战
文章转载自:https://mp.weixin.qq.com/s/_0RlojDsE30CeDSyLNP44w 1.问题引出 ES中文社区中,有如下问题: 问题1:存储数据,data目录从一个机器直接 ...
- 连接FastDFS出现超时问题的解决办法
1.使用Java语言写的web项目,jeecg框架连接FastDFS,需要修改的信息如下: # WEB-INF/classes/fdfs_client.conf connect_timeout=300 ...
- 7M与N的数学运算
m=eval(input()) n=eval(input()) a=m+n b=m*n c=m**n d=m%n e=max(m,n) print(a,b,c,d,e)
- 计算机三大硬件和操作系统以及python解释器
今日分享内容概要 计算机五大组成部分详解 计算机三大核心硬件 操作系统 编程与编程语言 编程语言的发展历史 编程语言的分类 python解释器 python解释器多版本共存 分享详细 计算机五大组成部 ...
- ES6中的数组reduce()方法详解
reduce() 方法对数组中的每个元素执行一个由我们提供的reducer函数(升序执行),将其结果汇总为单个返回值. 1. 语法reduce说明 arr.reduce(callback(accumu ...
- PTA 1126 Eulerian Path
无向连通图,输出每个顶点的度并判断Eulerian.Semi-Eulerian和Non-Eulerian这3种情况,我们直接记录每个点所连接的点,这样直接得到它的度,然后利用深度优先和visit数组来 ...
- Sqoop 之 安装
Sqoop 之 安装 前言 安装 Sqoop 的前提是已经具备 Java 和 Hadoop 的环境. 一.下载并解压 1) 下载地址:http://mirrors.hust.edu.cn/apache ...
- tensorboard图表显示不全的问题
之前跑bcq生成tensorboard文件的时候,有二十个点用来描图,然而后10个数据点总是不显示,之后将tensorboard换成tensorboardX便解决了问题. 比如 from torch. ...
- PHP配置负载均衡
我项目是用宝塔面板.所以这次用宝塔面板演示. 环境: LNMP 代码:2套.2套代码除了配置其他都是一样 域名:1个.2级域名.其实一级二级都没关系 /************************ ...
- Vue学习之--------列表排序(ffilter、sort、indexOf方法的使用)、Vue检测数据变化的原理(2022/7/15)
文章目录 1.列表排序 1.1 .代码实例 1.2 .测试效果 1.3.需要掌握的前提知识 2.Vue监测数据变化的原理 2.1.代码实例 2.2 .测试效果 3.Vue检测数据的原理 3.1 基本知 ...