Spark从入门到精通第十六课:Spark SQL的udf函数和udaf函数 && 开窗函数

本篇博客详细讲解了Spark SQL中的用户自定义函数(UDF)和用户自定义聚合函数(UDAF),分别探讨了在Spark 2.x和3.x中弱类型和强类型的udaf用法。此外,还深入介绍了如何运用开窗函数进行复杂的数据分析操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、UDF函数的使用 

1、注册时直接写逻辑
    ss.udf.register("length",(x:String)=>(x.length))

2、udaf函数的使用(弱类型是spark2.x)

1、继承UserDefinedAggregateFunction类,复写八个方法。session.udf.register("函数名",new MyUDF());注册

2、八个方法:
    inputSchema 输入类型  
    bufferSchema  缓冲区类型  
    dataType  输出类型  
    deterministic 稳定性函数,传入相同参数结果是否一样。 
    initialize 缓冲区初始化函数  
    update 如何更新缓冲区 
    merge 多节点下不同节点缓冲区如何合并  
    evalute 基于缓冲区如何计算得出结果
package com.lirong

import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types._
import org.apache.spark.sql.{DataFrame, Row, SparkSession}


public class MyUDAF extends UserDefinedAggregateFunction  {

  //输入类型
  def inputSchema: StructType = {
    DataTypes.createStructType(Array(
        DataTypes.createStructField("input", LongType, true)
        )
    )
  }

  // 缓冲区类型
  def bufferSchema: StructType = {
    DataTypes.createStructType(Array(
        DataTypes.createStructField("total", LongType, true),
        DataTypes.createStructField("count", LongType, true)
        )
    )
  }

  // 输出类型
  def dataType: DataType = {
    DataTypes.LongType
  }

  //稳定性函数:多次运行,相同的输入是否得到相同的输出。true为是
  def deterministic: Boolean = {
      true
  }

  //缓冲区初始化函数
  def initialize(buffer: MutableAggregationBuffer): Unit = {
    buffer.update(0,0L)   //参数1为角标,参数2为值
    buffer.update(1,0L)   //参数1为角标,参数2为值
  }

  // 如何更新缓冲区
  def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    buffer.update(0,buffer.getLong(0)+input.getLong(0))
    buffer.update(1,buffer.getLong(1)+1)
  }

  // 多节点下各个节点缓冲区合并
  def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
    buffer.update(0,buffer1.getLong(0)+buffer2.getLong(0))
    buffer.update(1,buffer1.getLong(1)+buffer2.getLong(1))
  }


  //缓冲区数据如何进行计算
  def evaluate(buffer: Row): Any = {
    buffer.getLong(0)/buffer.getLong(1)
  }


}

3、udaf函数的使用(强类型spark 3.x)

1、继承aggregator函数,泛型为输入输出缓冲区类型,复写六个方法。session.udf.register("函数名",functions.udf(new MyUDF()));注册

2、六个方法:
    zero:缓冲区初始化函数。
    reduce  如何更新缓冲区  
    merge 多节点洗啊不同节点缓冲区如何合并  
    evalute  基于缓冲区如何计算得出结果  
    bufferEncoder   缓冲区编码操作,解决跨节点传输问题
    outputEncoder   输出编码操作,解决跨节点传输问题

3、其实spark 2.x也能使用强类型的udaf函数,但注册函数时需要以DSL方式将UDAF定义成查询语句的一列,比较麻烦。

4、弱类型不会对输入数据的类型做判断,传入啥就用啥计算,类型不对会报错。而强类型不会。

开窗函数

开窗函数
    所谓开窗函数,就是在对数据进行分组,然后给数据打上一个组内的序号。
    如果要实现分组求top n,只需要对排序的字段进行过滤即可。

    标准格式:
        row_number() over (partitin by xxx order by yyy) z
    解释:
        partitin by xxx:    
                根据xxx字段进行分组。
        order by yyy:
                根据yyy字段进行排序。
        z:
            别名。可用于过滤 

示例:
    select riqi,leibie,jine from (
        select riqi,leibie,jine,
        row_number() over (partition by leibie order by jine desc) rank from sales) t          
        where t.rank<=3;

    ###求每类商品中销售金额排名前3的日期。
     MySQL 8之后也支持开窗函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二百四十九先森

你的打赏是我努力的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值