spark2.4.0 sql dataframe向上补齐操作(含udaf操作)

10 篇文章 0 订阅
5 篇文章 0 订阅

方案一

使用窗口函数以及index实现

具体操作放大图查看
在这里插入图片描述

方案二

使用窗口函数的特性以及spark2.4.0 新的array特性进行结合

具体操作放大图查看
在这里插入图片描述
其中所指的窗口函数

聚合函数(index索引) over(order by index rows between unbounded preceding and current row)

表示针对每一行的记录来说。只计算当前行的index 之前所有行到当前行的范围内对指定字段进行聚合计算,
此窗口函数类似于神经网络中的卷积层,用来扫描一定范围内的数据,并对这些数据进行指定操作。

在spark sql 中的catelog逻辑执行计划项目中,对于窗口函数的聚类计算做了一定层度的优化,其会保留上次窗口得到的结果,以及重叠状态依次进行如下计算,因此相率还是可以的

方案三使用 udaf创建自定义用户聚合函数,用来注册到sparksession中

package com.homewell.feature.udaf

import org.apache.spark.sql.Row
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types.{DataType, DoubleType, StructField, StructType}

class UpperUDAF extends UserDefinedAggregateFunction{
   // 用户输入 schema
  override def inputSchema: StructType = StructType(
    StructField("metric" , DoubleType)::Nil
  )
  // 在shuffle过程中的中间过程schema
  override def bufferSchema: StructType = StructType(
    StructField("mid" , DoubleType)::Nil
  )
 // 定义udaf最终输出的格式
  override def dataType: DataType = DoubleType
  // 数学概念中的最终一致性
  override def deterministic: Boolean = true
  // 初始化中间变量值
  override def initialize(buffer: MutableAggregationBuffer): Unit = {
    buffer.update(0,null)
  }
  // 用后面的函数更新数据值
  override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
    println("buffer",buffer )
    val inputvalue = input.get(0)
    val before = buffer.get(0)
    println("update ", inputvalue)
    if(inputvalue !=null) {
      buffer.update(0, inputvalue)
    }
  }
  // shuffle合并的时候出现的情况
  override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
    val leftvalue = buffer1.get(0)
    val rightvalue = buffer2.get(0)
    if(rightvalue !=null) {
      buffer1.update(0, rightvalue)
    }
  }
  // 获取原数据
  override def evaluate(buffer: Row): Double = {
    return buffer.getDouble(0)
  }
}

用户只要继承spark 提供的UserDefinedAggregateFunction接口
并注册到spark中 如下使用


    val conf = new SparkConf().setAppName("adb").setMaster("local")
//    val sc = new SparkContext(conf)
    val scc = SparkSession.builder().config(conf).getOrCreate()
    scc.udf.register("upperfill", new UpperUDAF())
    val txt: DataFrame = scc.read.format("csv")
      .option("sep",",")
      .option("inferSchema", "true")
      .option("header", "true")
      .load("data/udafupper.txt")
    txt.createOrReplaceTempView("txt")
    import scc.sql
    val data: DataFrame = sql("select *,upperfill(score) over(order by name) as upper from txt")
    data.show()

±--------±----±----+
| name|score|upper|
±--------±----±----+
| zhangll| 99| 99.0|
|zhangll17| null| 99.0|
| zhangll2| 98| 98.0|
| zhangll3| 85| 85.0|
| zhangll4| null| 85.0|
| zhangll5| 87| 87.0|
±--------±----±----+

思考

向下补齐,同理,不过最好对指定列进行降序排序,再用窗口函数,否则性能会有所损失

如有不对的地方请不吝赐教

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

乾坤瞬间

您的鼓励是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值