SparkSQL学习笔记(一)

一、DataFrame和DataSet

DataFrame是一个分布式数据容器,除了记录数据以外,还记录数据的结构信息。

Dataset是一个由特定领域的对象组成强类型(typedrel)集合,可以使用函数(DSL)或关系运算(SQL)进行并行的转换操作。

Dataset可以认为是DataFrame的一个特例,并且Dataset和DataFrame都是懒加载的,只有触发行动算子才会执行操作。

二、创建sparkSQL的运行环境

首先引入maven项目

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.12</artifactId>
    <version>3.1.1</version>
</dependency>
def main(args: Array[String]): Unit = {
  val conf: SparkConf = new SparkConf().setAppName("sql").setMaster("local")
  
  // 由于sparksession的构造方法是私有的所以不能通过new的方式,sparkSession底层封装了sparkContext
  val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
  session.close()   
}

三、创建DataFrame,DataSet

创建DataFrame以及两种操作方式。

// 创建dataFrame   type DataFrame = Dataset[Row]就是一个特殊类型的dataSet
val df: DataFrame = session.read.json("datas/user.json")
df.show()

// 通过sql的方式操纵df
df.createGlobalTempView("globalUser")  //创建全局视图
df.createOrReplaceTempView("user")     // 创建临时视图
session.sql("select * from user").show()  // 直接写sql语句去查询视图,show是展示结果

// 通过sdl的方式操纵df
import session.implicits._  //  引入转换规则,否则不识别$,也可以用'代替$

// as 是别名,filter 就是类似where操作
df.select($"id" + 1 as "pp").filter($"damage" > 90).show

创建DataSet

import session.implicits._  // 这里是前面的引入规则
val datas = Seq(1, 2, 3, 4)
val dataSet: Dataset[Int] = datas.toDS()
dataSet.show()

四、DataFrame、DataSet、RDD的相互转换

// RDD转换成dataframe
val rdd = session.sparkContext.makeRDD(List((1, "zhangsan", 30),(3, "wangwu", 40)))
val dataFrame = rdd.toDF("id", "name", "age") // 转换成DF,里面传列名
val changeRdd: RDD[Row] = dataFrame.rdd       // dataframe转换成rdd

// dataframe转换成dataSet
val ds = dataFrame.as[User]  // 根据样例类来进行转换 
val changeFrame = ds.toDF()  // 转换成changeFrame

// rdd转换dataSet  需要首先给dataSet进行转换
val ds1 = rdd.map(item => {
  User(item._1, item._2, item._3)
}).toDS()
val rdd1 = ds1.rdd  // 转换成RDD

// 提供数据结构的样例类
case class User(var id:Int, var name:String, var age:Int)

五、用户自定义函数

第一种姿势

def main(args: Array[String]): Unit = {
  val conf: SparkConf = new SparkConf().setAppName("sql").setMaster("local")
  val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()   
  import session.implicits._
  val dataFrame = session.read.json("datas/user.json")
  dataFrame.createOrReplaceTempView("user")

  // 通过udf注册自定义函数,两个参数:函数名和实现
  session.udf.register("prefix", (name: String) => {"zyz"+name})

  session.sql("select prefix(damage) from user").show()
  session.close()
}

弱类型的姿势:直接修改sql语句,现在已经不推荐使用了

object Sql01 {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("sql").setMaster("local")
    val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
    import session.implicits._
    val dataFrame = session.read.json("datas/user.json")
    dataFrame.createOrReplaceTempView("user")

    // 通过udf注册自定义类
    session.udf.register("prefix", new MyUAF)
    session.sql("select prefix(damage) from user").show()

    session.close()
  }

  // 弱类型方式自定义类  弱类型是指修改sql语句,现在不推荐了
  class MyUAF extends UserDefinedAggregateFunction{

    // 输入结构
    override def inputSchema: StructType = {
      StructType(Array(StructField("damage", IntegerType)))
    }

    // 缓冲区做计算的结构, 放中间变量和最后变量
    override def bufferSchema: StructType = {
      StructType(Array(StructField("total", IntegerType), StructField("count", IntegerType)))
    }

    // 计算结果的数据类型
    override def dataType: DataType = IntegerType

    // 函数的稳定性,传入相同的参数结果是否相同
    override def deterministic: Boolean = true

    // 缓冲区初始化
    override def initialize(buffer: MutableAggregationBuffer): Unit = {
      buffer.update(0, 0) // 第一个参数代表索引位置,第二个代表初始值
      buffer.update(1, 0)
    }

    // 每次读入数据缓冲区如何更新
    override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
      buffer.update(0, buffer.getInt(0) + input.getInt(0))
      buffer.update(1, buffer.getInt(1) + 1)
    }

    // 缓冲区数据合并
    override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
      buffer1.update(0, buffer1.getInt(0) + buffer2.getInt(0))
      buffer1.update(1, buffer1.getInt(1) + buffer2.getInt(1))
    }

    // 计算
    override def evaluate(buffer: Row): Any = {
      buffer.getInt(0) / buffer.getInt(1)
    }
  }
}

强类型的姿势

object Sql01 {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("sql").setMaster("local")
    val session: SparkSession = SparkSession.builder().config(conf).getOrCreate()
    import session.implicits._
    val dataFrame = session.read.json("datas/user.json")
    dataFrame.createOrReplaceTempView("user")

    // 通过udf注册自定义函数
    session.udf.register("prefix", functions.udaf(new MyUAF))
    session.sql("select prefix(damage) from user").show()
    session.close()
  }

  // 作为中间缓冲区的类
  case class Buf(var total: Int, var count: Int){}

  //  强类型的方式  需要传 IN, BUF, OUT  三种泛型(输入类型 缓冲区类型 输出类型)
  class MyUAF extends Aggregator[Int, Buf ,Int]{

    // 初始值,缓冲区初始化
    override def zero: Buf = Buf(0, 0)

    // 根据输入的数据更新缓冲区的数据
    override def reduce(b: Buf, a: Int): Buf = {
      b.total += a
      b.count += 1
      b
    }

    // 合并缓冲区
    override def merge(b1: Buf, b2: Buf): Buf = {
      b1.total += b2.total
      b1.count += b2.count
      b1
    }

    // 计算
    override def finish(reduction: Buf): Int = {
      reduction.total / reduction.count
    }

    // 缓冲区的编码操作,自定义的类就是product
    override def bufferEncoder: Encoder[Buf] = Encoders.product

    // 输出的编码操作
    override def outputEncoder: Encoder[Int] = Encoders.scalaInt
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值