【SparkSQL】Spark SQL自定义函数的介绍及其使用

本文详细介绍了Spark中自定义函数的应用,包括UDF(User-Defined Function)和UDAF(User-Defined Aggregation Function)。通过实例展示了如何使用UDF转换数据,并利用UDAF计算平均值,深入解析了UDAF的实现机制。

目录

介绍

自定义UDF

自定义UDAF


  • 介绍

类似于hive当中的自定义函数, spark同样可以使用自定义函数来实现新的功能。spark中的自定义函数有如下3类

UDF(User-Defined-Function):输入一行,输出一行

UDAF(User-Defined Aggregation Funcation):输入多行,输出一行

UDTF(User-Defined Table-Generating Functions):输入一行,输出多行

 

  • 自定义UDF

数据

Hello
abc
study
small

 

通过自定义UDF函数将每一行数据转换成大写

//创建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()

//根据SparkSession创建SparkContext
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")

//读取文件
val fileDS: Dataset[String] = spark.read.textFile("C:\\Users\\86132\\Desktop\\555\\udf.txt")


//将每一行数据转换成大写
//注册一个函数名称为smallToBig,功能是传入一个String,返回一个大写的String
spark.udf.register("smallToBig", (str: String) => str.toUpperCase())
fileDS.createOrReplaceTempView("t_word")

//使用我们自己定义的函数
spark.sql("select value,smallToBig(value) from t_word").show()

sc.stop()
spark.stop()

 

  • 自定义UDAF

数据

{"name":"Michael","salary":3000}
{"name":"Andy","salary":4500}
{"name":"Justin","salary":3500}
{"name":"Berta","salary":4000}

继承UserDefinedAggregateFunction方法重写说明

inputSchema:输入数据的类型

bufferSchema:产生中间结果的数据类型

dataType:最终返回的结果类型

deterministic:确保一致性,一般用true

initialize:指定初始值

update:每有一条数据参与运算就更新一下中间结果(update相当于在每一个分区中的运算)

merge:全局聚合(将每个分区的结果进行聚合)

evaluate:计算最终的结果

 

求取平均工资

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

    //根据SparkSession创建SparkContext
    val sc: SparkContext = spark.sparkContext
    sc.setLogLevel("WARN")

    //读取文件
    val employeeDF: DataFrame = spark.read.json("C:\\Users\\86132\\Desktop\\555\\udaf.json")

    //创建临时表
    employeeDF.createOrReplaceTempView("t_employee")

    //注册UDAF函数
    spark.udf.register("myavg", new MyUDAF)

    //使用自定义UDAF函数
    spark.sql("select myavg(salary) from t_employee").show()

    //使用内置的avg函数
    spark.sql("select avg(salary) from t_employee").show()
  }
}

class MyUDAF extends UserDefinedAggregateFunction {
  //输入的数据类型的schema
  override def inputSchema: StructType = {
    //:: Nil 创建一个不可变的列表
    StructType(StructField("input", LongType) :: Nil)
  }

  //缓冲区数据类型schema,就是转换之后的数据的schema
  override def bufferSchema: StructType = {
    StructType(StructField("sum", LongType) :: StructField("total", LongType) :: Nil)
  }

  //返回值的数据类型
  override def dataType: DataType = {
    DoubleType
  }

  //确定是否相同的输入会有相同的输出
  override def deterministic: Boolean = {
    true
  }

  //初始化内部数据结构
  override def initialize(buffer: MutableAggregationBuffer): Unit = {
    buffer(0) = 0L
    buffer(1) = 0L
  }

  //更新数据内部结构,区内计算
  override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    //所有的金额相加
    buffer(0) = buffer.getLong(0) + input.getLong(0)
    //一共有多少条数据
    buffer(1) = buffer.getLong(1) + 1
  }

  //来自不同分区的数据进行合并,全局合并
  override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
    buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0)
    buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
  }

  //计算输出数据值
  override def evaluate(buffer: Row): Any = {
    buffer.getLong(0).toDouble / buffer.getLong(1)
  }

 

SparkSQL 中,可以通过 `spark.udf.register` 方法来创建和使用用户自定义函数UDF)。以下是如何实现的基本步骤: ### 创建 UDF 1. **定义 DataFrame**:读取数据源并生成一个 DataFrame。例如: ```scala val df = spark.read.json("data/user.json") ``` 该语句从 JSON 文件中加载数据,并将其转换为 DataFrame。 2. **注册 UDF**:通过 `spark.udf.register` 注册一个自定义函数。例如,定义一个将字符串前缀添加到输入值的函数: ```scala spark.udf.register("addName", (x: String) => "Name:" + x) ``` 这里第一个参数是注册的函数名,第二个参数是一个 Lambda 表达式,用于定义具体的功能[^2]。 3. **创建临时表**:为了方便后续 SQL 查询,可以将 DataFrame 转换为临时表: ```scala df.createOrReplaceTempView("people") ``` 4. **调用 UDF**:通过 SQL 查询语句直接调用注册的 UDF: ```scala spark.sql("SELECT addName(name), age FROM people").show() ``` 此查询会输出带有前缀 `"Name:"` 的名字以及对应的年龄信息[^2]。 ### 示例代码 以下是一个完整的示例代码: ```scala // 初始化 SparkSession val spark = SparkSession.builder() .appName("CustomUDFExample") .master("local[*]") .getOrCreate() // 读取 JSON 数据生成 DataFrame val df = spark.read.json("data/user.json") // 注册 UDF 函数 spark.udf.register("addName", (x: String) => "Name:" + x) // 创建临时表 df.createOrReplaceTempView("people") // 使用 UDF 查询数据 spark.sql("SELECT addName(name), age FROM people").show() ``` ### 注意事项 - 在定义 UDF 时,需要确保返回值类型与实际逻辑匹配。 - 避免在 UDF 中进行复杂的计算或操作,因为这可能会影响性能。 - 可以通过匿名函数或者命名函数的形式定义 UDF,具体取决于需求和代码可维护性。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值