Spark 自定义函数(udf,udaf)
Spark 版本 2.3
文中测试数据(json)
{"name":"lillcol", "age":24,"ip":"192.168.0.8"}
{"name":"adson", "age":100,"ip":"192.168.255.1"}
{"name":"wuli", "age":39,"ip":"192.143.255.1"}
{"name":"gu", "age":20,"ip":"192.168.255.1"}
{"name":"ason", "age":15,"ip":"243.168.255.9"}
{"name":"tianba", "age":1,"ip":"108.168.255.1"}
{"name":"clearlove", "age":25,"ip":"222.168.255.110"}
{"name":"clearlove", "age":30,"ip":"222.168.255.110"}
用户自定义udf
自定义udf的方式有两种
- SQLContext.udf.register()
- 创建UserDefinedFunction
这两种个方式 使用范围不一样
package com.test.spark
import org.apache.spark.sql.expressions.UserDefinedFunction
import org.apache.spark.sql.functions.udf
import org.apache.spark.sql.{Dataset, Row, SparkSession}
/**
* @author Administrator
* 2019/7/22-14:04
*
*/
object TestUdf {
val spark = SparkSession
.builder()
.appName("TestCreateDataset")
.config("spark.some.config.option", "some-value")
.master("local")
.enableHiveSupport()
.getOrCreate()
val sQLContext = spark.sqlContext
import spark.implicits._
def main(args: Array[String]): Unit = {
testudf
}
def testudf() = {
val iptoLong: UserDefinedFunction = getIpToLong()
val ds: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
ds.createOrReplaceTempView("table1")
sQLContext.udf.register("addName", sqlUdf(_: String)) //addName 只能在SQL里面用 不能在DSL 里面用
//1.SQL
sQLContext.sql("select *,addName(name) as nameAddName from table1")
.show()
//2.DSL
val addName: UserDefinedFunction = udf((str: String) => ("ip: " + str))
ds.select($"*", addName($"ip").as("ipAddName"))
.show()
//如果自定义函数相对复杂,可以将它分离出去 如iptoLong
ds.select($"*", iptoLong($"ip").as("iptoLong"))
.show()
}
def sqlUdf(name: String): String = {
"name:" + name
}
/**
* 用户自定义 UDF 函数
*
* @return
*/
def getIpToLong(): UserDefinedFunction = {
val ipToLong: UserDefinedFunction = udf((ip: String) => {
val arr: Array[String] = ip.replace(" ", "").replace("\"", "").split("\\.")
var result: Long = 0
var ipl: Long = 0
if (arr.length == 4) {
for (i <- 0 to 3) {
ipl = arr(i).toLong
result |= ipl << ((3 - i) << 3)
}
} else {
result = -1
}
result
})
ipToLong
}
}
输出结果
+---+---------------+---------+--------------+
|age| ip| name| nameAddName|
+---+---------------+---------+--------------+
| 24| 192.168.0.8| lillcol| name:lillcol|
|100| 192.168.255.1| adson| name:adson|
| 39| 192.143.255.1| wuli| name:wuli|
| 20| 192.168.255.1| gu| name:gu|
| 15| 243.168.255.9| ason| name:ason|
| 1| 108.168.255.1| tianba| name:tianba|
| 25|222.168.255.110|clearlove|name:clearlove|
| 30|222.168.255.110|clearlove|name:clearlove|
+---+---------------+---------+--------------+
+---+---------------+---------+-------------------+
|age| ip| name| ipAddName|
+---+---------------+---------+-------------------+
| 24| 192.168.0.8| lillcol| ip: 192.168.0.8|
|100| 192.168.255.1| adson| ip: 192.168.255.1|
| 39| 192.143.255.1| wuli| ip: 192.143.255.1|
| 20| 192.168.255.1| gu| ip: 192.168.255.1|
| 15| 243.168.255.9| ason| ip: 243.168.255.9|
| 1| 108.168.255.1| tianba| ip: 108.168.255.1|
| 25|222.168.255.110|clearlove|ip: 222.168.255.110|
| 30|222.168.255.110|clearlove|ip: 222.168.255.110|
+---+---------------+---------+-------------------+
+---+---------------+---------+----------+
|age| ip| name| iptoLong|
+---+---------------+---------+----------+
| 24| 192.168.0.8| lillcol|3232235528|
|100| 192.168.255.1| adson|3232300801|
| 39| 192.143.255.1| wuli|3230662401|
| 20| 192.168.255.1| gu|3232300801|
| 15| 243.168.255.9| ason|4087938825|
| 1| 108.168.255.1| tianba|1823014657|
| 25|222.168.255.110|clearlove|3735617390|
| 30|222.168.255.110|clearlove|3735617390|
+---+---------------+---------+----------+
用户自定义 UDAF 函数(即聚合函数)
弱类型用户自定义聚合函数
通过继承UserDefinedAggregateFunction
package com.test.spark
import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
import org.apache.spark.sql.types._
import org.apache.spark.sql.{Dataset, Row, SparkSession}
/**
* @author lillcol
* 2019/7/22-15:09
* 弱类型用户自定义聚合函数
*/
object TestUDAF extends UserDefinedAggregateFunction {
// 聚合函数输入参数的数据类型
// :: 用于的是向队列的头部追加数据,产生新的列表,Nil 是一个空的 List,定义为 List[Nothing]
override def inputSchema: StructType = StructType(StructField("age", IntegerType) :: Nil)
//等效于
// override def inputSchema: StructType=new StructType() .add("age", IntegerType).add("name", StringType)
// 聚合缓冲区中值的数据类型
override def bufferSchema: StructType = {
StructType(StructField("sum", IntegerType) :: StructField("count", IntegerType) :: Nil)
}
// UserDefinedAggregateFunction返回值的数据类型。
override def dataType: DataType = DoubleType
// 如果这个函数是确定的,即给定相同的输入,总是返回相同的输出。
override def deterministic: Boolean = true
// 初始化给定的聚合缓冲区,即聚合缓冲区的零值。
override def initialize(buffer: MutableAggregationBuffer): Unit = {
// sum, 总的年龄
buffer(0) = 0
// count, 人数
buffer(1) = 0
}
// 使用来自输入的新输入数据更新给定的聚合缓冲区。
// 每个输入行调用一次。(同一分区)
override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
buffer(0) = buffer.getInt(0) + input.getInt(0) //年龄 叠加
buffer(1) = buffer.getInt(1) + 1 //人数叠加
}
// 合并两个聚合缓冲区并将更新后的缓冲区值存储回buffer1。
// 当我们将两个部分聚合的数据合并在一起时,就会调用这个函数。(多个分区)
override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getInt(0) + buffer2.getInt(0) //年龄 叠加
buffer1(1) = buffer1.getInt(1) + buffer2.getInt(1) //人数叠加
}
override def evaluate(buffer: Row): Any = {
buffer.getInt(0).toDouble / buffer.getInt(1)
}
val spark = SparkSession
.builder()
.appName("Spark SQL basic example")
// .config("spark.some.config.option", "some-value")
.master("local[*]") // 本地测试
.getOrCreate()
import spark.implicits._
def main(args: Array[String]): Unit = {
spark.udf.register("myAvg", TestUDAF)
val ds: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
ds.createOrReplaceTempView("table1")
//SQL
spark.sql("select myAvg(age) as avgAge from table1")
.show()
//DSL
val myavg = TestUDAF
ds.select(TestUDAF($"age").as("avgAge"))
.show()
}
}
输出结果:
+------+
|avgAge|
+------+
| 31.75|
+------+
+------+
|avgAge|
+------+
| 31.75|
+------+
强类型用户自定义聚合函数
通过继承Aggregator(是org.apache.spark.sql.expressions 下的 不要引错包了)
package com.test.spark
import org.apache.spark.sql.{Dataset, Encoder, Encoders, SparkSession}
import org.apache.spark.sql.expressions._
/**
* @author Administrator
* 2019/7/22-16:07
*
*/
// 既然是强类型,可能有 case 类
case class Person(name: String, age: Double, ip: String)
case class Average(var sum: Double, var count: Double)
object MyAverage extends Aggregator[Person, Average, Double] {
// 此聚合的值为零。应该满足任意b + 0 = b的性质。
// 定义一个数据结构,保存工资总数和工资总个数,初始都为0
override def zero: Average = {
Average(0, 0)
}
// 将两个值组合起来生成一个新值。为了提高性能,函数可以修改b并返回它,而不是为b构造新的对象。
// 相同 Execute 间的数据合并(同一分区)
override def reduce(b: Average, a: Person): Average = {
b.sum += a.age
b.count += 1
b
}
// 合并两个中间值。
// 聚合不同 Execute 的结果(不同分区)
override def merge(b1: Average, b2: Average): Average = {
b1.sum += b2.sum
b1.count += b2.count
b1
}
// 计算最终结果
override def finish(reduction: Average): Double = {
reduction.sum.toInt / reduction.count
}
// 为中间值类型指定“编码器”。
override def bufferEncoder: Encoder[Average] = Encoders.product
// 为最终输出值类型指定“编码器”。
override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
val spark = SparkSession
.builder()
.appName("Spark SQL basic example")
// .config("spark.some.config.option", "some-value")
.master("local[*]") // 本地测试
.getOrCreate()
import spark.implicits._
def main(args: Array[String]): Unit = {
val ds: Dataset[Person] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson").as[Person]
ds.show()
val avgAge = MyAverage.toColumn/*.name("avgAge")*///指定该列的别名为avgAge
ds.select(avgAge)//执行avgAge.as("columnName") 汇报org.apache.spark.sql.AnalysisException错误 别名只能在上面指定(目前测试是这样)
.show()
}
}
输出结果:
+---+---------------+---------+
|age| ip| name|
+---+---------------+---------+
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
+---+---------------+---------+
+------+
|avgAge|
+------+
| 31.75|
+------+
本文为原创文章,转载请注明出处!!!
Spark 自定义函数(udf,udaf)的更多相关文章
- 大数据学习day29-----spark09-------1. 练习: 统计店铺按月份的销售额和累计到该月的总销售额(SQL, DSL,RDD) 2. 分组topN的实现(row_number(), rank(), dense_rank()方法的区别)3. spark自定义函数-UDF
1. 练习 数据: (1)需求1:统计有过连续3天以上销售的店铺有哪些,并且计算出连续三天以上的销售额 第一步:将每天的金额求和(同一天可能会有多个订单) SELECT sid,dt,SUM(mone ...
- spark自定义函数之——UDAF使用详解及代码示例
UDAF简介 UDAF(User Defined Aggregate Function)即用户定义的聚合函数,聚合函数和普通函数的区别是什么呢,普通函数是接受一行输入产生一个输出,聚合函数是接受一组( ...
- Hive 自定义函数 UDF UDAF UDTF
1.UDF:用户定义(普通)函数,只对单行数值产生作用: 继承UDF类,添加方法 evaluate() /** * @function 自定义UDF统计最小值 * @author John * */ ...
- Spark(十三)SparkSQL的自定义函数UDF与开窗函数
一 自定义函数UDF 在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_ ...
- hive自定义函数UDF UDTF UDAF
Hive 自定义函数 UDF UDTF UDAF 1.UDF:用户定义(普通)函数,只对单行数值产生作用: UDF只能实现一进一出的操作. 定义udf 计算两个数最小值 public class Mi ...
- SparkSQL中的自定义函数UDF
在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...
- 10_Hive自定义函数UDF
Hive官方的UDF手册地址是:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 1.使用内置函数的快捷方法: 创 ...
- T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst、语言版本影响!
原文:T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst.语言版本影响! CSDN 的 Blog 太滥了!无时不刻地在坏! 开始抢救性搬家 ...
- Hadoop生态圈-Hive的自定义函数之UDAF(User-Defined Aggregation Function)
Hadoop生态圈-Hive的自定义函数之UDAF(User-Defined Aggregation Function) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.
- 三 Hive 数据处理 自定义函数UDF和Transform
三 Hive 自定义函数UDF和Transform 开篇提示: 快速链接beeline的方式: ./beeline -u jdbc:hive2://hadoop1:10000 -n hadoop 1 ...
随机推荐
- robotium学习
20140424 控件种类:spinner:下拉菜单,可以选择:TabHost:可以左右滑动,比如电话本:Gallery:rogressbar进度条;DatePicker;CheckBox,Radio ...
- python培训拾遗
20140421 1. 三大利器: dir----列出所有内部方法 a=1 dir(a) 可以列出所有内部方法,就是带两个下划线的:带一个下划线的是普通方法 help---查看帮助 help(a.bi ...
- json格式化在线工具推荐
现在系统对接基本都采用json格式的报文,杂乱无章的json让人看起来头大,这里推荐一款在线格式化json的工具, 工具地址: http://www.matools.com/json 这个在线Json ...
- 4. Jmeter主界面的介绍
上篇文章我们已经介绍过如何安装Jmeter.那么在本篇文章我们将要介绍Jmeter主界面有哪些功能.我们双击jmeter.bat,如下图所示(注意我这是jmeter5.0版本): 我们将Jmter主界 ...
- Linux关闭端口
1. 查看哪些端口被占用 $ netstat -anp | grep 2042 tcp 0 0 192.168.56.1:2042 0.0.0.0:* LISTEN 8974/python 2. 删 ...
- 前端(十六)—— JavaScript盒子模型、JS动画、DOM、BOM
JS盒子模型.JS动画.DOM.BOM 一.JS盒模型 1.width | height parseInt(getComputedStyle(ele, null).getPropertyValue(' ...
- Java多态的实现机制是什么,写得非常好!
作者:crane_practice www.cnblogs.com/crane-practice/p/3671074.html Java多态的实现机制是父类或接口定义的引用变量可以指向子类或实现类的实 ...
- 骑马修栅栏 Riding the Fences
题目背景 Farmer John每年有很多栅栏要修理.他总是骑着马穿过每一个栅栏并修复它破损的地方. 题目描述 John是一个与其他农民一样懒的人.他讨厌骑马,因此从来不两次经过一个栅栏.你必须编一个 ...
- vue keep-alive缓存问题
搬运自:https://blog.csdn.net/dongguan_123/article/details/80910231 我的问题:列表页 > 详情页a > 支付页 > ...
- Hadoop–TaskTracker 相关
TaskTracker 是Hadoop集群中运行于各个节点上的服务.他是JobTracker和Task之间的"通信桥梁".一方面它从JobTracker端接受并执行各种命令:比如运 ...