Spark SQL自定义函数

第1关:Spark SQL自定义函数(UDF)

编程要求

  • 文件路径:/data/workspace/myshixun/step1/student.txt;
  • 依据左侧的知识点介绍,处理student.txt文件:
    • 依据english打上标签“分数<70”、“70<分数<80”、“分数>80”;
    • 将 subject 列中的分隔符统一为“/”。

student.txt文件内容如下:

studentID,name,sex,english,subject
20220411,张三,m,65,Python Hadoop MySQL HBase
20220412,王五,f,70,机器学习、数据挖掘 Python
20220413,李四,m,72,JavaWeb/Java/HTML/JQuery
20220414,韩梅梅,f,78,大数据基础与应用/Linux/Hadoop、Java
20220415,李雷,m,85,模具设计、C++
20220416,马冬梅,f,88,Java、HTML/JavaWeb/MySQL

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{Dataset, SparkSession}

/********** Begin **********/
object createUDF {

  def main(args: Array[String]): Unit = {
    //创建spark对象
    val spark = SparkSession.builder().master("local[*]").appName("createUDF").getOrCreate()

    //创建上下文对象
    val sc: SparkContext = spark.sparkContext

    //导入隐式转换
    import spark.implicits._

    //读取文件,跳过首行,转换成dataframe
    val data_txt = sc.textFile("/data/workspace/myshixun/step1/student.txt").map(x => {
      val line = x.split(","); (line(0), line(1), line(2), line(3), line(4))})

    //去除首行
    val firstline = data_txt.first()
    val df = data_txt.filter(_ != firstline).toDF("studentID","name","sex","english","subject")

    //展示数据
    df.show(false)

    //注册自定义函数
    spark.udf.register("transform",(x:String)=>{
      if (x.contains("、")){
        x.replace("、","/")
      }else if(x.contains(" ")){
        x.replace(" ","/")
      }else{
        x
      }
    })
    spark.udf.register("scoreTag",(x:Int)=>{
      if (x<70){
        "分数<70"
      }else if (70<x && x<80){
        "70<分数<80"
      }else{
        "分数>80"
      }
    })

    //注册临时视图
    df.createOrReplaceTempView("df")

    //使用自定义函数
    spark.sql("select name,scoreTag(english) as scoretag,transform(subject) as subject from df".stripMargin).show(false)
    //关闭资源
    spark.close()

  }

}
/********** End **********/

第2关:Spark SQL自定义聚合函数(UDAF)

知识点

用户在自定义聚合函数时,须要继承 Aggregator[IN,BUF,OUT] 抽象类,还必须重写这个类中的zero、reduce、merge、finish、bufferEncoder、outputEncoder 这几个函数。

Aggregator 中的类型介绍:

  • IN : 聚合的输入类型

  • BUF : 减少的中间值的输入类型

  • OUT : 最终输出结果的类型

对于 Aggregator 类中重写这几个函数的介绍如下所示:

  • zero : BUF 聚合的中间结果的初始值。

  • reduce(b: BUF,a: IN) : BUF 将输入值聚合a为当前中间值。为了性能,该函数可能会修改b并返回它,而不是构造一个新对象。

  • merge(b1: BUF, b2: BUF) : BUF 合并两个中间值。

  • finish(reduction: BUF): OUT 最终的结果输出。

  • bufferEncoder:Encoder[BUF] 指定中间值类型的编码器。

  • outputEncoder: Encoder[OUT] 指定最终输出值类型的编码器。

编程要求

使用自定义聚合函数求取学科最优成绩。 文件路径如下:/data/workspace/myshixun/step2/salary.txtsalary.txt部分文件内容如下:

Cendy,3000
Andy,4500
Justin,3500
Mike,4000
......

import org.apache.spark.sql.{Encoder, Encoders, SparkSession, functions}
import org.apache.spark.sql.expressions.Aggregator
import org.apache.log4j.{Level, Logger}

/********** Begin **********/
object createUDAF {
  //定义聚合缓冲器类型
  case class Buff(var salary:Long)
  //创建自定义函数
  class MyMaxFunction extends Aggregator[Long,Buff,Long]{
    //初始化
    override def zero: Buff = Buff(Integer.MIN_VALUE)

    //局部计算逻辑
    override def reduce(acc: Buff, sal: Long): Buff = {
      if (sal>acc.salary){acc.salary=sal}
      acc
    }

    //合并计算结果
    override def merge(acc1: Buff, acc2: Buff): Buff = {
      if (acc1.salary>acc2.salary) {acc1}
      else {acc2}
    }

    //综合计算
    override def finish(reduction: Buff): Long = reduction.salary

    //缓冲区的编码设置
    override def bufferEncoder: Encoder[Buff] = Encoders.product

    //输出的编码设置
    override def outputEncoder: Encoder[Long] = Encoders.scalaLong
  }

  def main(args: Array[String]): Unit = {
    //设置日志级别
    Logger.getLogger("org").setLevel(Level.ERROR)
    //创建spark对象
    val spark = SparkSession.builder().appName("strongUDAF")
      .config("spark.testing.memory", "2147480000").master("local[*]").getOrCreate()

    //导入隐式转换
    import spark.implicits._
    //读取数据
     val data1 = spark.read.textFile("/data/workspace/myshixun/step2/salary.txt").filter(row=>row!=null && row.length>0).map(x=>{
      val line = x.split(",");
      (line(0),line(1).toLong)
    }).toDF("name","salary")

    //创建临时视图
    data1.createOrReplaceTempView("df")

    //注册函数
    val mymaxfunc = new MyMaxFunction
    spark.udf.register("MaxFunc",functions.udaf(mymaxfunc))

    //使用函数
     spark.sql("select MaxFunc(salary) from df").show(false)

    //关闭资源
    spark.close()
  }

}
/********** End **********/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值