除了逐行处理数据的udf,还有比较常见的就是聚合多行处理udaf,自定义聚合函数。类比rdd编程就是map和reduce算子的区别。
自定义UDAF,需要extends org.apache.spark.sql.expressions.UserDefinedAggregateFunction,并实现接口中的8个方法。
udaf写起来比较麻烦,我下面列一个之前写的取众数聚合函数,在我们通常在聚合统计的时候可能会受某条脏数据的影响。
举个栗子:
对于一个app日志聚合的时候,有id与ip,原则上一个id有一个ip,但是在多条数据里有一条ip是错误的或者为空的,这时候group能会聚合成两条数据了就,如果使用max,min对ip也进行聚合,那也不太合理,这时候可以进行投票,去类似多数对结果,从而聚合后只有一个设备。
废话少说,上代码:
import org.apache.spark.sql.Row
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types._ /**
* Description: 自定义聚合函数:众数(取列内频率最高的一条)
*/ class UDAFGetMode extends UserDefinedAggregateFunction {
override def inputSchema: StructType = {
StructType(StructField("inputStr", StringType, true) :: Nil)
} override def bufferSchema: StructType = {
StructType(StructField("bufferMap", MapType(keyType = StringType, valueType = IntegerType), true) :: Nil)
} override def dataType: DataType = StringType override def deterministic: Boolean = false //初始化map
override def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer() = scala.collection.immutable.Map[String, Int]()
} //如果包含这个key则value+1,否则写入key,value=1
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
val key = input.getAs[String]()
val immap = buffer.getAs[Map[String, Int]]()
val bufferMap = scala.collection.mutable.Map[String, Int](immap.toSeq: _*)
val ret = if (bufferMap.contains(key)) {
// val new_value = bufferMap.get(key).get + 1
val new_value = bufferMap(key) +
bufferMap.put(key, new_value)
bufferMap
} else {
bufferMap.put(key, )
bufferMap
}
buffer.update(, ret) } override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
//合并两个map 相同的key的value累加
val tempMap = (buffer1.getAs[Map[String, Int]]() /: buffer2.getAs[Map[String, Int]]()) {
case (map, (k, v)) => map + (k -> (v + map.getOrElse(k, )))
}
buffer1.update(, tempMap)
} override def evaluate(buffer: Row): Any = {
//返回值最大的key
var max_value =
var max_key = ""
buffer.getAs[Map[String, Int]]().foreach({ x =>
val key = x._1
val value = x._2
if (value > max_value) {
max_value = value
max_key = key
}
})
max_key
}
}

测试类:

object UDAFTest {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().master("local").appName(this.getClass.getSimpleName).getOrCreate()
spark.udf.register("get_mode", new UDAFGetMode)
import spark.implicits._
val df = Seq(
(, "10.10.1.1", "start"),
(, "10.10.1.1", "search"),
(, "123.123.123.1", "search"),
(, "10.10.1.0", "stop"),
(, "123.123.123.1", "start")
).toDF("id", "ip", "action") df.createTempView("tb")
spark.sql(s"select id,get_mode(ip) as u_ip,count(*) as cnt from tb group by id").show()
}
}

UDAF(用户自定义聚合函数)求众数的更多相关文章

  1. Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  2. hive学习笔记之十:用户自定义聚合函数(UDAF)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<hive学习笔记>的第十 ...

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

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

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

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

  5. SQL Server 2008 R2——PIVOT 行转列 以及聚合函数的选择

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  6. 2、SQL基础整理(聚合函数)

    聚合函数 --求平均 select  AVG(age) as 年龄 from xuesheng select AVG(chinese) as 语文 from xuesheng where class ...

  7. Hive学习之自己定义聚合函数

    Hive支持用户自己定义聚合函数(UDAF),这样的类型的函数提供了更加强大的数据处理功能. Hive支持两种类型的UDAF:简单型和通用型.正如名称所暗示的,简单型UDAF的实现很easy,但因为使 ...

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

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

  9. Mongodb学习笔记四(Mongodb聚合函数)

    第四章 Mongodb聚合函数 插入 测试数据 ;j<;j++){ for(var i=1;i<3;i++){ var person={ Name:"jack"+i, ...

随机推荐

  1. 物联网架构成长之路(27)-Docker练习之Zookeeper安装

    0. 前言 准备了解一下消息队列MQ,对比了一些开源的中间件,最后选择Kafka作为以后用到的消息队列,消息队列的应用场景及Kafka与其他消息队列的优缺点这里就不细说了,具体的可以参考其他博客说明. ...

  2. Linux下C语言执行shell命令

    有时候在代码中需要使用到shell命令的情况,下面就介绍一下怎么在C语言中调用shell命令: 这里使用popen来实现,关于popen的介绍,查看 http://man7.org/linux/man ...

  3. [转]SOA架构设计经验分享—架构、职责、数据一致性

    阅读目录: 1.背景介绍 2.SOA的架构层次 2.1.应用服务(原子服务) 2.2.组合服务 2.3.业务服务(编排服务) 3.SOA化的重构 3.1.保留服务空间,为了将来服务的组合 4.运用DD ...

  4. Web API 异常处理

    Web Api的ExceptionFilter只能截获并处理Action执行过程中发生的异常,在Action执行过程之外如果出现异常,ExceptionFilter是无能为力的. 这些异常包括: 1. ...

  5. Python2.x与3.x版本区别

    Python2.x与3.x版本区别 1.print 函数 print语句没有了,取而代之的是print()函数. Python 2.6与Python 2.7部分地支持这种形式的print语法.在Pyt ...

  6. SQL 性能分析

    SELECT s2.dbid, s1.sql_handle, (SELECT TOP SUBSTRING(s2.text,statement_start_offset / + , ( (CASE WH ...

  7. ViZDoom深度预测(Depth Prediction)

    代码:github.com/huangshiyu13/ViZDoomDepth 图片被分成3x6的区域,利用模型预测每个区域的平均深度,效果如下图:

  8. 如何让linux的history命令显示时间记录

    在.bashrc文件追加如下内容即可: HISTFILESIZE= HISTSIZE= HISTTIMEFORMAT='%F %T ' export HISTTIMEFORMAT

  9. tensorflow冻结变量方法(tensorflow freeze variable)

    最近由于项目需要,要对tensorflow构造的模型中部分变量冻结,然后继续训练,因此研究了一下tf中冻结变量的方法,目前找到三种,各有优缺点,记录如下: 1.名词解释 冻结变量,指的是在训练模型时, ...

  10. 库存秒杀问题-redis解决方案- 接口限流

    <?php/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 1 ...