spark编写UDF和UDAF
UDF:
一、编写udf类,在其中定义udf函数
package spark._sql.UDF import org.apache.spark.sql.functions._ /**
* AUTHOR Guozy
* DATE 2019/7/18-9:41
**/
object udfs {
def len(str: String): Int = str.length def ageThan(age: Int, small: Int): Boolean = age > small val ageThaner = udf((age: Int, bigger: Int) => age < bigger)
}
二、在主方法中进行调用
package spark._sql import org.apache.log4j.Logger
import org.apache.spark.sql
import spark._sql.UDF.udfs._
import org.apache.spark.sql.functions._ /**
* AUTHOR Guozy
* DATE 2019/7/18-9:42
**/
object UDFMain {
val log = Logger.getLogger("UDFMain") def main(args: Array[String]): Unit = {
val ssc = new sql.SparkSession.Builder()
.master("local[2]")
.appName(this.getClass.getSimpleName)
.enableHiveSupport()
.getOrCreate() ssc.sparkContext.setLogLevel("warn") val df = ssc.createDataFrame(Seq((22, 1), (24, 1), (11, 2), (15, 2))).toDF("age", "class_id")
df.createOrReplaceTempView("table") ssc.udf.register("len", len _)
ssc.sql("select age,len(age) as len from table").show(20, false)
println("=====================================")
ssc.udf.register("ageThan", ageThan _)
ssc.sql("select age from table where ageThan(age,15)").show()
println("=====================================")
import ssc.implicits._
val r = ssc.sql("select * from table")
r.filter(ageThaner($"age", lit(20))).show()
println("=====================================") ssc.stop()
}
}
运行结果:
可以看到,以上代码中一共定义了三个不同的udf函数,分别对三个函数进行说明:
len(str: String):该函数使用用来获取传入字段的长度,str 即为所需要传入的字段
- 在使用的时候,需要现将其进行注册并赋予其函数名:ssc.udf.register("len", len _),调用的时候直接在sql语句中通过函数名来进行调用
ageThan(age: Int, small: Int):该函数式用来比较传入的age与已有的small大小,返回一个boolean值,该函数需要是用在where条件语句中用来进行过滤使用
- 在使用的时候,需要现将其进行注册并赋予其函数名:ssc.udf.register("ageThan", ageThan _),调用的时候直接在sql语句中通过函数名来进行调用
ageThaner:该函数跟上面两个不同,所谓的不同指的是:
- 定义方式不同:通过使用org.apache.spark.sql.functions._ 中的udf函数在定义的时候就将其注册好
- 使用场景不同:使用在dataframe中,用来进行select,filter操作中
- 对于该函数的第二列来说,如果是常量的话,需要使用org.apache.spark.sql.function._ 中的lit进行包装,不能将常量直接传入,否则,程序不认识该常量会报错,如果是列名的话,则没问题,使用($"colName")方式即可。
UDAF:
UDAF相对于udf来说稍微麻烦一下,且需要完全理解当中每个函数的含义才可以轻而易举的写出符合自己预期的UDAF函数,
UDAF需要继承 UserDefinedAggregateFunction ,并且复写当中的方法
方法含义说明:
def inputSchema: StructType = StructType(Array(StructField("value", IntegerType)))
inputSchema用来定义,输入的字段的类型,字段名可以随便定义,这里定义为value,也可以是其他的,不重要,关键是字段类型一定要与所要传入计算的字段进行对应,且必须使用org.apche.spark.sql.type. _ 中的类型
def bufferSchema: StructType = StructType(Array( StructField("count", IntegerType), StructField("ages", DoubleType)))
bufferSchema用来定义生成中间数据的结果类型,例如在求和的时候,要求a+b+c,相加顺序为a+b=ab,ab+c=abc ,ab即为中间结果。
def dataType: DataType = DoubleType
dataType为函数返回值的类型,例子中,该UDAF最终返回的结果为double类型,这里的类型不能写成double,要写成org.apache.spark.sql.type._支持的类型DoubleType.
def deterministic: Boolean = true
daterministic 为代表结果是否为确定性的,也就是说,相同的输入是否有相同的输出。
def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0) = 0
buffer(1) = 0.0
}
initalize 初始化中间结果,即count和ages的初始值。
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
buffer(0) = buffer.getInt(0) + 1 //更新计数器
buffer(1) = buffer.getDouble(1) + input.getInt(0) //更新值
}
update用来更新中间结果,input为dataframe中的一行,将要合并到buffer中的数据,buffer则为已经进行合并后的中间结果。
def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getInt(0) + buffer2.getInt(0)
buffer1(1) = buffer1.getDouble(1) + buffer2.getDouble(1)
}
merge 合并所有分片的结果,buffer2是一个分片的中间结果,buffer1是整个合并过程中的结果。
def evaluate(buffer: Row): Any = {
buffer.getDouble(1) / buffer.getInt(0)
}
evaluate 函数式真正进行计算的函数,计算返回函数的结果,buffer是merge合并后的结果
案例需求:求分组中age的平均数
先上代码:
一、定义UDAF函数
package spark._sql.UDAF import org.apache.spark.sql.Row
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types._ /**
* AUTHOR Guozy
* DATE 2019/7/18-14:47
**/
class udafs() extends UserDefinedAggregateFunction { def inputSchema: StructType = StructType(Array(StructField("value", IntegerType))) def bufferSchema: StructType = StructType(Array( StructField("count", IntegerType), StructField("ages", DoubleType))) def dataType: DataType = DoubleType def deterministic: Boolean = true def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0) = 0
buffer(1) = 0.0
} override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
buffer(0) = buffer.getInt(0) + 1 //更新计数器
buffer(1) = buffer.getDouble(1) + input.getInt(0) //更新值
} def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getInt(0) + buffer2.getInt(0)
buffer1(1) = buffer1.getDouble(1) + buffer2.getDouble(1)
} def evaluate(buffer: Row): Any = {
buffer.getDouble(1) / buffer.getInt(0)
}
}
二、主函数引用:
package spark._sql.UDF import org.apache.spark.sql
import org.apache.spark.sql.functions._
import spark._sql.UDAF.udafs /**
* AUTHOR Guozy
* DATE 2019/7/19-16:04
**/
object UDAFMain {
def main(args: Array[String]): Unit = {
val ssc = new sql.SparkSession.Builder()
.master("local[2]")
.appName(this.getClass.getSimpleName)
.enableHiveSupport()
.getOrCreate() ssc.sparkContext.setLogLevel("warn") val ageDF = ssc.createDataFrame(Seq((22, 1), (24, 1), (11, 2), (15, 2))).toDF("age", "class_id")
ssc.udf.register("avgage", new udafs)
ageDF.createOrReplaceTempView("table")
ssc.sql("select avgage(age) from table group by class_id").show() ssc.stop()
}
}
运行结果:
spark编写UDF和UDAF的更多相关文章
- Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十五)Spark编写UDF、UDAF、Agg函数
Spark Sql提供了丰富的内置函数让开发者来使用,但实际开发业务场景可能很复杂,内置函数不能够满足业务需求,因此spark sql提供了可扩展的内置函数. UDF:是普通函数,输入一个或多个参数, ...
- 【Spark篇】---SparkSQL中自定义UDF和UDAF,开窗函数的应用
一.前述 SparkSQL中的UDF相当于是1进1出,UDAF相当于是多进一出,类似于聚合函数. 开窗函数一般分组取topn时常用. 二.UDF和UDAF函数 1.UDF函数 java代码: Spar ...
- Spark Sql的UDF和UDAF函数
Spark Sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数hold不住,所以spark sql提供了可扩展的内置函数接口:哥们,你的业务太变态了 ...
- 详解Spark sql用户自定义函数:UDF与UDAF
UDAF = USER DEFINED AGGREGATION FUNCTION Spark sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数ho ...
- Hive 10、Hive的UDF、UDAF、UDTF
Hive自定义函数包括三种UDF.UDAF.UDTF UDF(User-Defined-Function) 一进一出 UDAF(User- Defined Aggregation Funcation) ...
- hive中UDF、UDAF和UDTF使用
Hive进行UDF开发十分简单,此处所说UDF为Temporary的function,所以需要hive版本在0.4.0以上才可以. 一.背景:Hive是基于Hadoop中的MapReduce,提供HQ ...
- 【Spark-SQL学习之三】 UDF、UDAF、开窗函数
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...
- 在hive中UDF和UDAF使用说明
Hive进行UDF开发十分简单,此处所说UDF为Temporary的function,所以需要hive版本在0.4.0以上才可以. 一.背景:Hive是基于Hadoop中的MapReduce,提供HQ ...
- 【转】hive中UDF、UDAF和UDTF使用
原博文出自于: http://blog.csdn.net/liuj2511981/article/details/8523084 感谢! Hive进行UDF开发十分简单,此处所说UDF为Tempora ...
随机推荐
- Linux中的系统服务_02
Linux中的系统服务_02 1. 在linux增加服务后,如果要实现随着操作系统的启动而启动,需要是用chkconfig命令,加入到系统服务中. 但是对于的脚本的表头,需要增加如下内容 #!/bin ...
- 每天一个Linux命令:rm(5)
rm rm命令可以删除一个目录中的一个或多个文件或目录,也可以将某个目录及其下属的所有文件及其子目录均删除掉.对于链接文件,只是删除整个链接文件,而原有文件保持不变 注意:使用rm命令要格外小心.因为 ...
- delphi 获取系统注册的文件图标
var Icon:TICON; Key : string; App : string; Index : Integer; begin FileName:=Edit6.Text; then begin ...
- 深入研究CSS
通常我们在学习CSS的时候,感觉很容易掌握,却常常在实际应用中碰到各式各样难以填补的“坑”,为避免大家受到同样的困惑与不解,本文详细讲解了CSS中优先级和Stacking Context等诸多高级特性 ...
- js 常用功能实现(函数)
1.10 个短小实用的代码片段 :https://www.jianshu.com/p/3ef822ec5a63 2.js常用函数 : https://www.cnblogs.com/wangyuyu ...
- AndroidManifest.xml配置文件详解(转)
转载博客:http://blog.csdn.net/shagoo/article/details/7485958# AndroidManifest.xml配置文件对于Android应用开发来说是非常重 ...
- USB3.0 对 2.4G WiFi 影响
Intel的一篇白皮书<USB 3.0 Radio Frequency Interference Impact on 2.4 GHz Wireless Devices>中即清楚地指出,US ...
- js少写if语句
1.if else if (bool) { a =1; } else { a = 2 } // 简写 a = bool ? 1 : 2: 2.if if (bool) { a = fn() } //简 ...
- Java继承和构造函数
构造函数不是类的成员,它们不是由子类继承的.它们用于初始化实例变量. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class CSuper { public ...
- 用Emacs进行Python开发
用Emacs进行Python开发 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} ...