UDF(User-Defined-Function)

UDF是用于处理一行数据的,接受一行输入产生一个输出,类似与map()算子,

UDAF(User- Defined Aggregation Funcation)

UDAF用于接收一组输入数据然后产生一个输出结果。

UDAF需要使用继承UserDefinedAggregateFunction的自定义类来实现功能,UserDefinedAggregateFunction中提供了8个抽象方法来帮助我们实现UDAF的构建。

public StructType inputSchema()

用于指定UDAF所输入数据的schmema的,也就是需要在这个方法类定义UDAF输入数据的字段的名称合字段的类型。

StructType bufferSchema()

因为UDAF是将数据进行聚合的,因此会使用到中间的临时变量进行数据存储,这个方法是用于定义这些中间的临时变量的Schema的。

DataType dataType()

这个方法是用于定义UDAF的返回结果的数据结构的。

boolean deterministic()

这个方法用于返回聚合函数是否是幂等的,即相同输入是否总是能得到相同输出。

为什么会有这个方法呢?这源于spark的推测执行(spark.speculation=true推测执行开启):推测执行是指对于Spark程序里面少部分运行慢的Task,会在其他节点的Executor上再次启动这个task,如果其中一个Task实例运行成功则将这个最先完成的Task的计算结果作为最终结果,同时会干掉其他Executor上运行的实例,从而加快运行速度。但是推测执行只有在函数是幂等的情况下才会这样运作,如果不是幂等的函数只会一直等待该Task执行。

void initialize(MutableAggregationBuffer buffer)

该方法用于初始化缓冲区的字段。

void update(MutableAggregationBuffer buffer, Row row)

该方法用于处理相同的executor间的数据合并,当有新的输入数据时,update用户更新缓存变量。

void merge(MutableAggregationBuffer buffer, Row row):

该方法用于不同excutor间已经进行初步聚合的数据进行合并。

Object evaluate(Row row):

通过前面的缓冲区完成聚合后,在这个方法里对聚合的字段进行最终的运算。

实例:

import org.apache.spark.sql.Row;
import org.apache.spark.sql.expressions.MutableAggregationBuffer;
import org.apache.spark.sql.expressions.UserDefinedAggregateFunction;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType; import java.util.ArrayList;
import java.util.List; public class MyUDAF extends UserDefinedAggregateFunction {
private StructType inputSchema;
private StructType bufferSchema; public MyUDAF() {
List<StructField> inputFields = new ArrayList<>();
inputFields.add(DataTypes.createStructField("inputColumn", DataTypes.DoubleType, true));
inputSchema = DataTypes.createStructType(inputFields); List<StructField> bufferFields = new ArrayList<>();
bufferFields.add(DataTypes.createStructField("sum", DataTypes.DoubleType, true));
bufferFields.add(DataTypes.createStructField("count", DataTypes.DoubleType, true));
bufferSchema = DataTypes.createStructType(bufferFields);
} //1、该聚合函数的输入参数的数据类型
public StructType inputSchema() {
return inputSchema;
} //2、聚合缓冲区中的数据类型.(有序性)
public StructType bufferSchema() {
return bufferSchema;
} //3、返回值的数据类型
public DataType dataType() {
return DataTypes.DoubleType;
} //4、这个函数是否总是在相同的输入上返回相同的输出,一般为true
public boolean deterministic() {
return true;
} //5、初始化给定的聚合缓冲区,在索引值为0的sum=0;索引值为1的count=1;
public void initialize(MutableAggregationBuffer buffer) {
buffer.update(0, 0D);
buffer.update(1, 0D);
} //6、更新
public void update(MutableAggregationBuffer buffer, Row input) {
//如果input的索引值为0的值不为0
if (!input.isNullAt(0)) {
double updateSum = buffer.getDouble(0) + input.getDouble(0);
double updateCount = buffer.getDouble(1) + 1;
buffer.update(0, updateSum);
buffer.update(1, updateCount);
}
} //7、合并两个聚合缓冲区,并将更新后的缓冲区值存储回“buffer1”
public void merge(MutableAggregationBuffer buffer1, Row buffer2) {
double mergeSum = buffer1.getDouble(0) + buffer2.getDouble(0);
double mergeCount = buffer1.getDouble(1) + buffer2.getDouble(1);
buffer1.update(0, mergeSum);
buffer1.update(1, mergeCount);
} //8、计算出最终结果
public Double evaluate(Row buffer) {
return buffer.getDouble(0) / buffer.getDouble(1);
}
}

main函数:

import org.apache.spark.SparkContext;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.api.java.UDF1;
import org.apache.spark.sql.types.DataTypes; import java.math.BigDecimal; public class UDAFJAVA {
public static void main(String[] args) {
SparkSession spark = SparkSession
.builder()
.appName("RunMyUDAF")
.master("local")
.getOrCreate();
SparkContext sc = spark.sparkContext();
sc.setLogLevel("ERROR"); // Register the function to access it
spark.udf().register("myAverage", new MyUDAF()); Dataset<Row> df = spark.read().json("D:\\02Code\\0901\\sd_demo\\src\\data\\udaf.json");
df.createOrReplaceTempView("employees");
df.show(); //保留两位小数,四舍五入
spark.udf().register("twoDecimal", new UDF1<Double, Double>() {
@Override
public Double call(Double in) throws Exception {
BigDecimal b = new BigDecimal(in);
double res = b.setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue();
return res;
}
}, DataTypes.DoubleType); Dataset<Row> result = spark
.sql("SELECT name,twoDecimal(myAverage(salary)) as avg_salary FROM employees group by name");
result.show();
spark.stop();
}
}

udaf.json:

{"name":"Michael","salary":0}
{"name":"Andy","salary":4537}
{"name":"Justin","salary":3500.0}
{"name":"Berta","salary":0}
{"name":"Michael","salary":3000.0}
{"name":"Andy","salary":4500.0}
{"name":"Justin","salary":3500.0}
{"name":"Berta","salary":4000.0}
{"name":"Andy","salary":4500.0}

Spark UDF/UDAF(JAVA)的更多相关文章

  1. Spark 自定义函数(udf,udaf)

    Spark 版本 2.3 文中测试数据(json) {"name":"lillcol", "age":24,"ip":& ...

  2. Spark(十三)【SparkSQL自定义UDF/UDAF函数】

    目录 一.UDF(一进一出) 二.UDAF(多近一出) spark2.X 实现方式 案例 ①继承UserDefinedAggregateFunction,实现其中的方法 ②创建函数对象,注册函数,在s ...

  3. 45、sparkSQL UDF&UDAF

    一.UDF 1.UDF UDF:User Defined Function.用户自定义函数. 2.scala案例 package cn.spark.study.sql import org.apach ...

  4. spark2.1注册内部函数spark.udf.register("xx", xxx _),运行时抛出异常:Task not serializable

    函数代码: class MySparkJob{ def entry(spark:SparkSession):Unit={ def getInnerRsrp(outer_rsrp: Double, we ...

  5. Spark 用户自定义函数 Java 示例

    Spark UDF Java 示例 在这篇文章中提到了用Spark做用户昵称文本聚类分析,聚类需要选定K个中心点,然后迭代计算其他样本点到中心点的距离.由于中文文字分词之后(n-gram)再加上昵称允 ...

  6. Spark之UDAF

    import org.apache.spark.sql.{Row, SparkSession} import org.apache.spark.sql.expressions.{MutableAggr ...

  7. UDF/UDAF开发总结

    参考文章: https://www.cnblogs.com/itxuexiwang/p/6264547.html https://www.cnblogs.com/eRrsr/p/6096989.htm ...

  8. 在spark udf中读取hdfs上的文件

    某些场景下,我们在写UDF实现业务逻辑时候,可能需要去读取某个文件. 我们可以将此文件上传个hdfs某个路径下,然后通过hdfs api读取该文件,但是需要注意: UDF中读取文件部分最好放在静态代码 ...

  9. UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现

      UserView--第二种方式(避免第一种方式Set饱和),基于Spark算子的java代码实现   测试数据 java代码 package com.hzf.spark.study; import ...

  10. UserView--第一种方式set去重,基于Spark算子的java代码实现

    UserView--第一种方式set去重,基于Spark算子的java代码实现 测试数据 java代码 package com.hzf.spark.study; import java.util.Ha ...

随机推荐

  1. 洛谷P2024 [NOI2001]食物链 种类并查集

    洛谷P2024 [NOI2001]食物链 题目描述 见食物链 - 洛谷 \(n\le5*10^4\) \(k\le10^5\) Recollection 初中的时候想了一个假掉了的算法想了很久. 刚刚 ...

  2. GC-QA-RAG 智能问答系统的文档切片

    本章节介绍 GC-QA-RAG 智能问答系统的文档切片原理,即如何将原始文档的知识点切片后存入向量数据库. 1. 原始思路 将整个文档作为输入,交由大语言模型自动生成问答对(QA Pairs),以支持 ...

  3. Spring扩展接口-FactoryBean

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  4. HyperMesh模型导入与几何清理

    2.1 CAD 模型导入与修复 HyperMesh 支持多种主流 CAD 格式模型文件,同时针对模型在软件之间导入导出过程中可能出现数据丢失的问题提供了多种修复工具. CAD 模型导入与修复可进行: ...

  5. java 获取访问的真实ip

    request 是 javax.servlet.http.HttpServletRequest 获取其他机器访问自己服务时的真实ip public String getIP(HttpServletRe ...

  6. Blazor学习之旅(7)布局

    大家好,我是Edison. 本篇,我们来了解下在Blazor中的布局. 什么是布局 Blazor 中的布局可以让我们编写的页面具有相同的导航菜单和页头页脚部分,提高通用代码的复用性,通过一次性的编写通 ...

  7. ASP.NET Core on K8S深入学习(3-1)Deployment

    本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 上一篇<部署过程解析与安装Dashboard>中我们了解K8S的部 ...

  8. 如何基于three.js(webgl)引擎架构,实现3D微信小游戏(第一课)

    引言 在三维图形和游戏开发领域,three.js 作为一个基于 WebGL 的 JavaScript 库,提供了强大的功能来创建和显示动画化的 3D 计算机图形.它使得开发者能够轻松地在网页上构建复杂 ...

  9. MKL普通矩阵运算示例及函数封装

    本示例将介绍MKL中的矩阵乘法和求逆,使用MKL进行此类大型矩阵运算可大量节省计算时间和空间,但由于MKL中的原生API接口繁杂,因此将常用函数封装,便于后续使用,最后在实际例子中调用接口执行想要的矩 ...

  10. 查看 SQL Server 当前的连接数

    打开 SQL Server Management Studio(SSMS),连接到 SQL Server 实例. 在 SSMS 的"对象资源管理器"窗格中,展开服务器节点. 点击& ...