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
  }

}
posted @ 2020-05-11 17:04  Q1Zhen  阅读(122)  评论(0编辑  收藏  举报