一. SparkSQL简介

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

Dremel ------> Drill(Apache)------>Impala(Cloudrea) Presto(Hotonworks)

Hive -------> Shark(对Hive的模仿,区别在于使用Spark进行计算)

Shark------->SparkSQL(希望拜托对Hive的依赖,兼容Hive)

SparkSQL: 如果使用SparkSQL执行Hive语句! 这种行为称为 Spark on Hive

​ 如果使用Hive,执行Hive语句,但是在配置Hive时,修改了Hive的执行引擎,将执行引擎修改为了Spark! 这种行为称为Hive on Spark!

特点

  • 易整合。 在程序中既可以使用SQL,还可以使用API!
  • 统一的数据访问。 不同数据源中的数据,都可以使用SQL或DataFrameAPI进行操作,还可以进行不同数据源的Join!
  • 对Hive的无缝支持
  • 支持标准的JDBC和ODBC

二. 数据模型

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

DataSet:是DataFrame的一个扩展,类似于数据库中的表。

区别

DataSet是强类型。DataSet=DataSet[Person].

DataFrame是弱类型。DataFrame=DataSet[Row],是DataSet的一个特例。

三. SparkSQL核心编程

Spark Core:要执行应用程序,要首先构建上下文环境对象SparkContext.

SparkSQL

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

最新的版本SparkSQL的查询入口是SparkSession。是SQLContext和HiveContext的组合,SparkSession内部封装了SparkContext

1. IDEA开发SparkSQL

pom依赖

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

2. SparkSession

创建

方式一

 import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession val session: SparkSession = SparkSession.builder
.master("local[*]")
.appName("MyApp")
.getOrCreate()

方式二

    val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MyApp")
val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
关闭
session.stop()
获取SparkContext
   session.sparkContext  //获取SparkSession中的SparkContext

3. DataFrame

3.1 入门案例
  /**
* DataFrame入门案例
*/
@Test
def createDF: Unit = {
//数据格式:{"username":"zhangsan","age":20}
//读取json格式文件创建DataFrame
val df: DataFrame = session.read.json("input/1.txt")
//创建临时视图:person
df.createOrReplaceTempView("person")
//查看person表
df.show()
//通过sql查询
session.sql(
"""
|select
|*
|from
|person
|""".stripMargin).show()
}
3.2 显示数据
df.show()
3.3 创建DF

①读取数据源创建

session.read
csv format jdbc json load option options orc parquet schema table text textFile

②通过RDD创建DataFrame

样例类

实际开发中,一般通过样例类将RDD转换为DataFrame

先导入隐式转换包,通过rdd.toDF()方法转换

 /**
* Person样例类
*/
case class Person(name: String, age: Int) /**
* 通过RDD创建DataFrame
*/
@Test
def creatDFByRDD {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MyApp")
val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
//根据样例类创建RDD
val rdd: RDD[(String, Int)] = session.sparkContext.makeRDD(List(("zhangsan", 12), ("lisi", 45), ("wangwu", 23)))
val person_RDD: RDD[Person] = rdd.map {
case (name, age) => Person(name, age)
}
//导入隐式包,session是上文创建的SparkSession对象
import session.implicits._
val df: DataFrame = person_RDD.toDF()
//查看DF
df.show()
session.stop()
}

③从hive表查询**

3.4 SQL查询语法

首先由DataFrame创建一个视图,然后用Sql语法操作

/*****************创建视图************************/
//临时视图
createOrReplaceTempView("视图名") //不会报错
createTempView("视图名") //视图名已存在,会报错
//永久视图
df.createGlobalTempView("person") /******************Sql查询*************************/
//临时视图:person
//查询全局视图需要添加:global_temp.person
session.sql(
"""
|select
|*
|from
|person
|""".stripMargin).show()

注意:普通临时表是Session范围内的,如果想应用范围内有效,可以使用全局临时表。使用全局临时表时需要全路径访问,如:global_temp.people

4. DataSet

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

4.1 创建DS

样例类RDD创建

 /**
* Person样例类
*/
case class Person(name: String, age: Int) /**
* 通过RDD创建DataFrame
*/
@Test
def creatDFByRDD {
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MyApp")
val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
//根据样例类创建RDD
val rdd: RDD[(String, Int)] = session.sparkContext.makeRDD(List(("zhangsan", 12), ("lisi", 45), ("wangwu", 23)))
val person_RDD: RDD[Person] = rdd.map {
case (name, age) => Person(name, age)
}
//导入隐式包,session是上文创建的SparkSession对象
import session.implicits._
val df: Dataset[Person] = person_RDD.toDS()
//查看DF
df.show()
session.stop()
}

基本类型的序列创建DataSet

val list: Seq[Int] = List(1, 2, 3, 4)
import session.implicits._
val df1 = list.toDS()

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

5. RDD、DataFrame、DataSet

三者的关系

相互转换



代码示例

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("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))) //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=>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)
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 ml同时使用

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://172.xx.xx.xx:9000/test")
datawDF.write.format("com.databricks.spark.csv").mode(SaveMode.Overwrite).options(saveoptions).save()
//读取
val options = Map("header" -> "true", "delimiter" -> "\t", "path" -> "hdfs://172.xx.xx.xx:9000/test")
val datarDF= spark.read.options(options).format("com.databricks.spark.csv").load()

利用这样的保存方式,可以方便的获得字段名和列的对应,而且分隔符(delimiter)可以自由指定

Dataset

这里主要对比Dataset和DataFrame,因为Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同

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]就能比较好的解决问题

转化

RDD、DataFrame、Dataset三者有许多共性,有各自适用的场景常常需要在三者之间转换

DataFrame/Dataset转RDD

这个转换很简单

val rdd1=testDF.rdd
val rdd2=testDS.rdd
RDD转DataFrame
import spark.implicits._
val testDF = rdd.map {line=>
(line._1,line._2)
}.toDF("col1","col2")

一般用元组把一行的数据写在一起,然后在toDF中指定字段名

RDD转Dataset
import spark.implicits._
case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
val testDS = rdd.map {line=>
Coltest(line._1,line._2)
}.toDS

可以注意到,定义每一行的类型(case class)时,已经给出了字段名和类型,后面只要往case class里面添加值即可

Dataset转DataFrame

这个也很简单,因为只是把case class封装成Row

import spark.implicits._
val testDF = testDS.toDF
DataFrame转Dataset
import spark.implicits._
case class Coltest(col1:String,col2:Int)extends Serializable //定义字段名和类型
val testDS = testDF.as[Coltest]

这种方法就是在给出每一列的类型后,使用as方法,转成Dataset,这在数据类型是DataFrame又需要针对各个字段处理时极为方便

特别注意

在使用一些特殊的操作时,一定要加上 import spark.implicits._ 不然toDF、toDS无法使用

总结:在对DataFrame和Dataset进行操作许多操作都需要这个包:import spark.implicits._(在创建好SparkSession对象后尽量直接导入)

Spark(十一)【SparkSQL的基本使用】的更多相关文章

  1. Hive On Spark和SparkSQL

    SparkSQL和Hive On Spark都是在Spark上实现SQL的解决方案.Spark早先有Shark项目用来实现SQL层,不过后来推翻重做了,就变成了SparkSQL.这是Spark官方Da ...

  2. 基于Spark和SparkSQL的NetFlow流量的初步分析——scala语言

    基于Spark和SparkSQL的NetFlow流量的初步分析--scala语言 标签: NetFlow Spark SparkSQL 本文主要是介绍如何使用Spark做一些简单的NetFlow数据的 ...

  3. Spark系列-SparkSQL实战

    Spark系列-初体验(数据准备篇) Spark系列-核心概念 Spark系列-SparkSQL 之前系统的计算大部分都是基于Kettle + Hive的方式,但是因为最近数据暴涨,很多Job的执行时 ...

  4. hive on spark VS SparkSQL VS hive on tez

    http://blog.csdn.net/wtq1993/article/details/52435563 http://blog.csdn.net/yeruby/article/details/51 ...

  5. Spark(四): Spark-sql 读hbase

    SparkSQL是指整合了Hive的spark-sql cli, 本质上就是通过Hive访问HBase表,具体就是通过hive-hbase-handler, 具体配置参见:Hive(五):hive与h ...

  6. Spark记录-SparkSql官方文档中文翻译(部分转载)

    1 概述(Overview) Spark SQL是Spark的一个组件,用于结构化数据的计算.Spark SQL提供了一个称为DataFrames的编程抽象,DataFrames可以充当分布式SQL查 ...

  7. Spark记录-SparkSQL相关学习

    $spark-sql  --help  查看帮助命令 $设置任务个数,在这里修改为20个 spark-sql>SET spark.sql.shuffle.partitions=20; $选择数据 ...

  8. Spark之 SparkSql整合hive

    整合: 1,需要将hive-site.xml文件拷贝到Spark的conf目录下,这样就可以通过这个配置文件找到Hive的元数据以及数据存放位置. 2,如果Hive的元数据存放在Mysql中,我们还需 ...

  9. Spark之 SparkSql、DataFrame、DataSet介绍

    SparkSql SparkSql是专门为spark设计的一个大数据仓库工具,就好比hive是专门为hadoop设计的一个大数据仓库工具一样. 特性: .易整合 可以将sql查询与spark应用程序进 ...

随机推荐

  1. UVA 10004 Bicoloring(DFS染色)

    题意: 给N个点构成的无环无向图,并且保证所有点对都是连通的. 给每个点染色,要么染成黑要么染成白.问是否存在染色方案使得所有有边相连的点对颜色一定不一样. 是输出 BICOLORABLE 否则输出 ...

  2. vue3.x版本路由router跳转+传参

    显示传参模式 get import { useRouter } from 'vue-router'; const router = useRouter(); let skipEdit = (key: ...

  3. Language Server for Java™ 1.0 在VS Code上正式发布!

    Nick Zhu form Senior Program Manager, Developer Division at Microsoft 今天,我们很高兴与大家宣布:Language Server ...

  4. 【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)

    问题描述 在使用Azure存储服务,为了有效的保护Storage的Access Keys.可以使用另一种授权方式访问资源(Shared Access Signature: 共享访问签名), 它的好处可 ...

  5. TestNG 参数化应用

    一.第一种参数化方式(testng.xml配置参数) 1.新建ParameterDemo04类 2.拷贝类的路径 3.testng.xml配置类地址及参数 <?xml version=" ...

  6. C++ Qt 项目实战(一)之文本编辑器

    文本编辑器例图 项目开发环境 系统版本:windows10 QT 版本: 5.9.9 开发语言:C++ 已实现功能 文件操作:新建,打开,保存,另存为,打印,退出 编辑操作:复制,粘贴,剪切,查找,替 ...

  7. vue项目部署到docker中

    通过nginx镜像部署 vue项目npm run build打包成dist目录,有的打包会加上版本号 启动 docker 将dist目录通过xftp拷贝到linux服务器上,同目录下新建Dockerf ...

  8. 面霸篇:Java 集合容器大满贯(卷二)

    面霸篇,从面试角度作为切入点提升大家的 Java 内功,所谓根基不牢,地动山摇. 码哥在 <Redis 系列>的开篇 Redis 为什么这么快中说过:学习一个技术,通常只接触了零散的技术点 ...

  9. 字符编码和python文件操作

    字符编码和文件操作 目录 字符编码和文件操作 1. 字符编码 1.1 什么是字符编码 1.2 字符编码的发展史 1.2.1 ASCII码 1.2.2 各国编码 1.2.3 Unicode 1.3 字符 ...

  10. [cf1361E]James and the Chase

    称一个点是"好点",当且仅当其到其余所有点恰存在一条简单路径 结论1:$x$为好点当且仅当以$x$为根的dfs树包含所有点且非树边均为返祖边 若不包含所有点,那么$x$到不被包含的 ...