SparkSQL
数据源
SparkSQL默认数据源为Parquet格式(面向列存储)。
将其他格式转换为Parquet后再读取
spark.read.format("json").load(path)
同样如果是保存,要将格式先进行转换,否则保存下来的数据为Parquet格式
df.write.format("json").mode("append").save(path)
1.从MySQL读取
val jdbcDF = spark.read.format("jdbc").option("url","jdbc:mysql://.....").option("dbtable",""tablename").ption("user","root").option("password","xxxx").load()
2.写入MySQL
jdbcDF.write.format("jdbc").option("url","jdbc:mysql://.....").option("dbtable",""tablename").ption("user","root").option("password","xxxx").save()
DataFrame
与RDD类似,DataFrame是一个分布式数据容器,更像传统数据库的二维表格,除了记录数据意以外,还记录数据的结构信息,即schema。同时,与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。从API易用性的角度上看,DataFrame API提供的是一套高层的关系操作,比函数式RDD API 更加友好,门槛更低。
1.创建方式
- 通过spark的数据源进行创建
spark.read.文件格式
-
从一个存在的RDD进行转换
- 手动确定转换RDD.toFD(字段名称)
- 通过反射确定(需要用到样例类)
- 通过编程方式 -
还可以从Hive Table进行查询返回
DataSet
是DataFrame API的一个扩展,是Spark最新的数据抽象,既具有类型安全检查也具有DataFrame的查询优化特性。支持编码器,当需要访问非堆上的数据时,可以避免反序列化整个对象,提高效率。DataFrame是DataSet的特例,DataFrame=DataSet[class]
1.创建方式
- RDD.toDS
需要用到样例类
- DF.as(类型)
在RDD与DF或者DS之间操作时,要引入隐式转换 import spark.implicits._
这里的spark不是包名,而是SparkSession对象
UDF自定义函数
spark.udf.register("methodname",(function))
一、自定义聚合函数(弱类型)
#1.声明自定义聚合函数
class MyFunction extends UserDefinedAggregateFunction{
#函数输入的数据结构
override def inputSchema:StructType = {
new StructType().add("age",LongType)
}
#计算时的数据结构
override def bufferSchema:StructType={
new StructType().add("sum",LongType).add("count",LongType)
}
#函数返回的数据类型
override def dataType:DataType= DoubleType
#函数是否稳定
override def deterministic:Boolean = true
#计算之前的缓冲区的初始化
override def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0)=0L #代表 bufferschema中第一个数据结构的初始化值
buffer(1)=1L
}
#将多个节点的缓冲区合并
override def merge(buffer1:MutableAggregationBuffer,buffer2:Row):Unit={
//sum
buffer1(0)=buffer1.getLong(0) + buffer2.getLong(0)
//count
buffer1(1)=buffer1.getLong(1) + buffer2.getLong(1)
}
#根据查询结果更新缓冲区的数据
override def update(buffer:MutableAggregationBuffer, input:Row):Unit={
buffer(0)= buffer.getLong(0) +input.getLong(0)
buffer(1)= buffer.getLong(0) + 1
}
#计算
override def evaluate(buffer:Row):Any={
buffer.getLong(0).toDouble/buffer.getLong(1)
}
}
#2.使用聚合函数
val udaf = new MyFunction()
spark.udf.register("xxx",udaf)
二、自定义聚合函数(强类型)
object UDFA_class {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[*]").setAppName("ooo")
val spark: SparkSession = SparkSession.builder().config(conf).getOrCreate()
import spark.implicits._
val udaf = new MyFunction()
//将聚合函数转换为查询列
val avgCol: TypedColumn[UserBean, Double] = udaf.toColumn.name("avgAge")
val frame = spark.read.json("in/user.json")
val userDS: Dataset[UserBean] = frame.as[UserBean]
userDS.select(avgCol).show()
spark.close()
}
case class UserBean (name : String, age : BigInt)
case class AvgBuffer(var sum:BigInt,var count:Int)
class MyFunction extends Aggregator[UserBean,AvgBuffer,Double]{
//缓冲区初始化
override def zero: AvgBuffer = {
AvgBuffer(0,0)
}
//聚合数据
override def reduce(b: AvgBuffer, a: UserBean): AvgBuffer = {
b.sum = b.sum+a.age
b.count=b.count+1
b
}
//两个节点缓冲区合并
override def merge(b1: AvgBuffer, b2: AvgBuffer): AvgBuffer = {
b1.sum=b1.sum+b2.sum
b1.count=b1.count+b2.count
b1
}
//完成计算
override def finish(reduction: AvgBuffer): Double = {
reduction.sum.toDouble/reduction.count
}
//如果是自己定义的类,就是Encoders.product,否则Encoders.scalaDouble
override def bufferEncoder: Encoder[AvgBuffer] = Encoders.product
override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
}
}