Spark SQL特点
1、易整合
整合SQL查询和Spark编程
2、统一的数据访问方式
使用相同方式连接不同的数据源
3、继承Hive
在已有的仓库上直接运行SQL或者HQL
4、标准的连接方式
通过JDBC或者ODBC
DataFrame
分布式数据容器
schema 数据的结构信息(类似于desc table)
支持嵌套数据类型 struct array map
从API易用性,DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好门槛更低
DataFrame懒执行,性能上比RDD高,原因:
优化的执行计划:
查询计划通过Spark catalyst optimiser进行优化
逻辑查询计划优化利用基于关系代数的等价变换,将高成本的操作替换为低成本操作的过程
DataSet(1.6 新增)
1、DataFrame API的扩展
2、友好的API风格
3、DataSet支持编解码器
4、样例类定义数据结构信息,映射到DataSet中的字段名称
5、DataFrame是DataSet的特列
6、DataFrame是强类型
Spark SQL编程
老版本中,SparkSQL查询起点是SQLContext
连接Hive的查询启动是HiveContext
2.0开始,SparkSession是Spark最新的SQL查询启动,实质是SQLContext和HiveContext,内部封装了SparkContext
DataFrame进行编程
创建DataFrame
1、通过Spark的数据源创建
val df = spark.read.json("../*.json")
2、通过已知的RDD来创建
3、通过查询一个Hive表创建
查看schema信息
df.printSchema
DataFrame语法风格
SQL语法风格(主要)
查询数据的时候使用SQL语句来查询
spark.sql("select * from people").show
DSL语法风格
提供一个特定领域语言区管理结构化的数据
df.select("name","age").show
RDD和DataFrame的交互
涉及到RDD、DataFrame、DataSet之间的操作,
需要导入import spark.implicts._
这里spark不是包名,而是表示SparkSession的对象
所以必须先创建SparkSession对象再导入,implicits是一个内部object
手动转换
rdd.toDF("name","age").show
样例类反射转换
case class People(name:String,age:Int)
样例把RDD转换成DataFrame
rdd.toDF.show
构建SparkSession
val spark: SparkSession = SparkSession.builder()
.master("local[*]")
.appName("Word Count")
.getOrCreate()
val sc: SparkContext = spark.sparkContext
映射RDD
val rowRdd:RDD[Row] = rdd.map(x=>Row(x._1,x._2))
创建StructType类型
val types = StructType(
Array(
StructField("name",StringType),
StructField("age",IntegerType)
)
)
创建DataFrame
val df:DataFrame = spark.createDataFrame(rowRdd,types)
显示
df.show
从DataFrame到RDD
rdd = df.rdd
得到的RDD中存储的数据类型是Row
DataSet编程
DataSet没有使用Java序列化或者Kryo序列化,而是使用一种专门的编码器区序列化对象,然后在网络上处理或者传输
编码器和标准序列化负责将对象转换成字节
创建DataSet
1、使用样例类的序列化
case class Person(name:String,age:Int)
为样例类创建编码器
val ds = Seq(
Person("lisi",20),
Person("zs",21)
).toDS
ds.show
2、使用基本类型的序列化
import spark.implicits._
val ds = Seq(1,2,3,4,5).toDS
ds.show
3、在实际使用的时候,更多的是通过RDD得到DataSet
RDD和DataSet的交互
1、从RDD到DataSet
使用反射来推断包含特定类型对象的RDD的schema
rdd.toDS
2、从DataSet到RDD
ds.rdd
DataFrame和DataSet交互
case class Person(name:String,age:Long)
1、DataFrame转换成DataSet
df.as[People]
2、DataSet转DataFrame
ds.toDF
RDD、DataFrame、DataSet之间的关系
版本
RDD (Spark1.0) —> Dataframe(Spark1.3) —> Dataset(Spark1.6)
三者的共性
1. RDD、DataFrame、Dataset全都是 Spark 平台下的分布式弹性数据集,为处理超大型数据提供便利
2. 三者都有惰性机制,在进行创建、转换,如map方法时,不会立即执行,只有在遇到Action如foreach时,三者才会开始遍历运算。
3. 三者都会根据 Spark 的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出
4. 三者都有partition的概念
5. 三者有许多共同的函数,如map, filter,排序等
6. 在对 DataFrame和Dataset进行操作许多操作都需要这个包进行支持 import spark.implicits._
7. DataFrame和Dataset均可使用模式匹配获取各个字段的值和类型
使用IDEA创建SparkSQL程序
添加SparkSQL依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.1.1</version>
</dependency>
自定义SparkSQL函数
在shell窗口中可以通过spark.udf功能用户可以自定义函数
//注册一个udf函数
//toUpper是函数名,第二个参数是函数的具体实现
spark.udf.register("toUpper",(s:String)=>s.toUpperCase)
用户自定义聚合函数
1、继承UserDefinedAggregateFunction
Object MyAvg extends UserDefinedAggregateFunction
2、注册自定义函数
spark.udf.register("myAvg",new MyAvg)
SparkSQL数据源
通用加载和保存函数
默认的数据源是parquet
spark.sql.sources.default设置默认的数据源
val usersDF = spark
.read.load("examples/src/main/resources/users.parquet")
usersDF.select("name", "favorite_color")
.write.save("namesAndFavColors.parquet")
spark.read.load是加载数据的通用做法
df.write.save是保存数据的通用方法
手动指定选项
val peopleDF = spark
.read.format("json")
.load("examples/src/main/resources/people.json")
peopleDF.select("name","age")
.write.format("parquet")
.save("namesAndAges.parquet")
在文件上直接运行SQL
spark.sql("select * from json")
加载json文件
SparkSession.read.format("json").load()
读取Parquet文件
Parquet 是一种流行的列式存储格式,
可以高效地存储具有嵌套字段的记录。
从jdbc读数据
val jdbcDF = spark.read
.format("jdbc")
.option("url", "jdbc:mysql://hadoop201:3306/rdd")
.option("user", "root")
.option("password", "aaa")
.option("dbtable", "user")
.load()
Hive数据库
使用外置的Hive
1.Spark 要接管 Hive 需要把 hive-site.xml copy 到conf/目录下.
2.把 Mysql 的驱动 copy 到 jars/目录下.
3.如果访问不到hdfs, 则需要把core-site.xml和hdfs-site.xml 拷贝到conf/目录下.