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的更多相关文章

  1. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十五)Spark编写UDF、UDAF、Agg函数

    Spark Sql提供了丰富的内置函数让开发者来使用,但实际开发业务场景可能很复杂,内置函数不能够满足业务需求,因此spark sql提供了可扩展的内置函数. UDF:是普通函数,输入一个或多个参数, ...

  2. 【Spark篇】---SparkSQL中自定义UDF和UDAF,开窗函数的应用

    一.前述 SparkSQL中的UDF相当于是1进1出,UDAF相当于是多进一出,类似于聚合函数. 开窗函数一般分组取topn时常用. 二.UDF和UDAF函数 1.UDF函数 java代码: Spar ...

  3. Spark Sql的UDF和UDAF函数

    Spark Sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数hold不住,所以spark sql提供了可扩展的内置函数接口:哥们,你的业务太变态了 ...

  4. 详解Spark sql用户自定义函数:UDF与UDAF

    UDAF = USER DEFINED AGGREGATION FUNCTION Spark sql提供了丰富的内置函数供猿友们使用,辣为何还要用户自定义函数呢?实际的业务场景可能很复杂,内置函数ho ...

  5. Hive 10、Hive的UDF、UDAF、UDTF

    Hive自定义函数包括三种UDF.UDAF.UDTF UDF(User-Defined-Function) 一进一出 UDAF(User- Defined Aggregation Funcation) ...

  6. hive中UDF、UDAF和UDTF使用

    Hive进行UDF开发十分简单,此处所说UDF为Temporary的function,所以需要hive版本在0.4.0以上才可以. 一.背景:Hive是基于Hadoop中的MapReduce,提供HQ ...

  7. 【Spark-SQL学习之三】 UDF、UDAF、开窗函数

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  8. 在hive中UDF和UDAF使用说明

    Hive进行UDF开发十分简单,此处所说UDF为Temporary的function,所以需要hive版本在0.4.0以上才可以. 一.背景:Hive是基于Hadoop中的MapReduce,提供HQ ...

  9. 【转】hive中UDF、UDAF和UDTF使用

    原博文出自于: http://blog.csdn.net/liuj2511981/article/details/8523084 感谢! Hive进行UDF开发十分简单,此处所说UDF为Tempora ...

随机推荐

  1. visulabox切换到菜单栏模式右ctrl + C

    2)首次看到1024x768的桌面时,查看可用的分辨率时,可能只能看到1024x768和800x600两种,其实,如果在virtualbox中按 右ctrl + C(Switch to Scaled ...

  2. MVC默认提供了一个异常过滤器 HandleErrorAttribte特性

    这一篇记录MVC默认提供了一个异常过滤器 HandleErrorAttribte,下一篇介绍自定义异常过滤特性. 参考引用:https://www.cnblogs.com/TomXu/archive/ ...

  3. Python3.5-20190513-廖老师-自我笔记-函数式编程

    把复杂的任务拆成各个小的函数,通过函数的调用来完成任务.这就是面向过程编程. 高阶函数:就是让函数的参数能够接收别的函数.把函数作为参数传入到另一个函数. 函数名也是变量.和变量用法一样的,指向一个函 ...

  4. Spring开发总结

    自动装载配置开启: spring.factories内容: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.b ...

  5. 微信JS-SDK接口上传图片以及wx.config的配置

    最近做的微信网页要实现一个上传图片的功能,倒腾了半天终于搞好了,具体的步骤可以查看微信官方文档https://developers.weixin.qq.com/doc/offiaccount/OA_W ...

  6. 大碗宽面Beta迭代阶段博客目录

    大碗宽面Beta迭代阶段博客目录 Githhub:https://github.com/rz-2000/Course-Evaluation 一.Scrum Meeting 1. [第十周会议记录]ht ...

  7. CDN技术详解(七)

    动态内容加速服务的实现 随着Web2.0的兴起,产生了动态网页.个性化内容.电子交易数据等内容的加速,这些就涉及了动态内容加速技术. 静态内容的加速,都是对于表现层的加速,对于动态页面等内容的加速,则 ...

  8. 【Java架构:基础技术】一篇文章搞掂:Idea

    一.使用技巧 1.1.配置Maven 打开File-Settings打开设置界面 1.2.配置JDK JDK可以设置默认版本,也可以设置针对某个项目 分别对应File-Other Setting-De ...

  9. 【Java架构:基础技术】一篇文章搞掂:Linux

    基于CentOS 一.安装[暂略] 二.使用和登录[赞略] 三.使用yum CentOS自带yum,这里暂时不介绍安装方式 四.使用yum安装JDK 1.检查系统是否有安装open-jdk rpm - ...

  10. DBA-io