Spark 版本 2.3

文中测试数据(json)

  1. {"name":"lillcol", "age":24,"ip":"192.168.0.8"}
  2. {"name":"adson", "age":100,"ip":"192.168.255.1"}
  3. {"name":"wuli", "age":39,"ip":"192.143.255.1"}
  4. {"name":"gu", "age":20,"ip":"192.168.255.1"}
  5. {"name":"ason", "age":15,"ip":"243.168.255.9"}
  6. {"name":"tianba", "age":1,"ip":"108.168.255.1"}
  7. {"name":"clearlove", "age":25,"ip":"222.168.255.110"}
  8. {"name":"clearlove", "age":30,"ip":"222.168.255.110"}

用户自定义udf

自定义udf的方式有两种

  1. SQLContext.udf.register()
  2. 创建UserDefinedFunction

这两种个方式 使用范围不一样

  1. package com.test.spark
  2. import org.apache.spark.sql.expressions.UserDefinedFunction
  3. import org.apache.spark.sql.functions.udf
  4. import org.apache.spark.sql.{Dataset, Row, SparkSession}
  5. /**
  6. * @author Administrator
  7. * 2019/7/22-14:04
  8. *
  9. */
  10. object TestUdf {
  11. val spark = SparkSession
  12. .builder()
  13. .appName("TestCreateDataset")
  14. .config("spark.some.config.option", "some-value")
  15. .master("local")
  16. .enableHiveSupport()
  17. .getOrCreate()
  18. val sQLContext = spark.sqlContext
  19. import spark.implicits._
  20. def main(args: Array[String]): Unit = {
  21. testudf
  22. }
  23. def testudf() = {
  24. val iptoLong: UserDefinedFunction = getIpToLong()
  25. val ds: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
  26. ds.createOrReplaceTempView("table1")
  27. sQLContext.udf.register("addName", sqlUdf(_: String)) //addName 只能在SQL里面用 不能在DSL 里面用
  28. //1.SQL
  29. sQLContext.sql("select *,addName(name) as nameAddName from table1")
  30. .show()
  31. //2.DSL
  32. val addName: UserDefinedFunction = udf((str: String) => ("ip: " + str))
  33. ds.select($"*", addName($"ip").as("ipAddName"))
  34. .show()
  35. //如果自定义函数相对复杂,可以将它分离出去 如iptoLong
  36. ds.select($"*", iptoLong($"ip").as("iptoLong"))
  37. .show()
  38. }
  39. def sqlUdf(name: String): String = {
  40. "name:" + name
  41. }
  42. /**
  43. * 用户自定义 UDF 函数
  44. *
  45. * @return
  46. */
  47. def getIpToLong(): UserDefinedFunction = {
  48. val ipToLong: UserDefinedFunction = udf((ip: String) => {
  49. val arr: Array[String] = ip.replace(" ", "").replace("\"", "").split("\\.")
  50. var result: Long = 0
  51. var ipl: Long = 0
  52. if (arr.length == 4) {
  53. for (i <- 0 to 3) {
  54. ipl = arr(i).toLong
  55. result |= ipl << ((3 - i) << 3)
  56. }
  57. } else {
  58. result = -1
  59. }
  60. result
  61. })
  62. ipToLong
  63. }
  64. }
  65. 输出结果
  66. +---+---------------+---------+--------------+
  67. |age| ip| name| nameAddName|
  68. +---+---------------+---------+--------------+
  69. | 24| 192.168.0.8| lillcol| name:lillcol|
  70. |100| 192.168.255.1| adson| name:adson|
  71. | 39| 192.143.255.1| wuli| name:wuli|
  72. | 20| 192.168.255.1| gu| name:gu|
  73. | 15| 243.168.255.9| ason| name:ason|
  74. | 1| 108.168.255.1| tianba| name:tianba|
  75. | 25|222.168.255.110|clearlove|name:clearlove|
  76. | 30|222.168.255.110|clearlove|name:clearlove|
  77. +---+---------------+---------+--------------+
  78. +---+---------------+---------+-------------------+
  79. |age| ip| name| ipAddName|
  80. +---+---------------+---------+-------------------+
  81. | 24| 192.168.0.8| lillcol| ip: 192.168.0.8|
  82. |100| 192.168.255.1| adson| ip: 192.168.255.1|
  83. | 39| 192.143.255.1| wuli| ip: 192.143.255.1|
  84. | 20| 192.168.255.1| gu| ip: 192.168.255.1|
  85. | 15| 243.168.255.9| ason| ip: 243.168.255.9|
  86. | 1| 108.168.255.1| tianba| ip: 108.168.255.1|
  87. | 25|222.168.255.110|clearlove|ip: 222.168.255.110|
  88. | 30|222.168.255.110|clearlove|ip: 222.168.255.110|
  89. +---+---------------+---------+-------------------+
  90. +---+---------------+---------+----------+
  91. |age| ip| name| iptoLong|
  92. +---+---------------+---------+----------+
  93. | 24| 192.168.0.8| lillcol|3232235528|
  94. |100| 192.168.255.1| adson|3232300801|
  95. | 39| 192.143.255.1| wuli|3230662401|
  96. | 20| 192.168.255.1| gu|3232300801|
  97. | 15| 243.168.255.9| ason|4087938825|
  98. | 1| 108.168.255.1| tianba|1823014657|
  99. | 25|222.168.255.110|clearlove|3735617390|
  100. | 30|222.168.255.110|clearlove|3735617390|
  101. +---+---------------+---------+----------+

用户自定义 UDAF 函数(即聚合函数)

弱类型用户自定义聚合函数

通过继承UserDefinedAggregateFunction

  1. package com.test.spark
  2. import org.apache.spark.sql.expressions.{MutableAggregationBuffer, UserDefinedAggregateFunction}
  3. import org.apache.spark.sql.types._
  4. import org.apache.spark.sql.{Dataset, Row, SparkSession}
  5. /**
  6. * @author lillcol
  7. * 2019/7/22-15:09
  8. * 弱类型用户自定义聚合函数
  9. */
  10. object TestUDAF extends UserDefinedAggregateFunction {
  11. // 聚合函数输入参数的数据类型
  12. // :: 用于的是向队列的头部追加数据,产生新的列表,Nil 是一个空的 List,定义为 List[Nothing]
  13. override def inputSchema: StructType = StructType(StructField("age", IntegerType) :: Nil)
  14. //等效于
  15. // override def inputSchema: StructType=new StructType() .add("age", IntegerType).add("name", StringType)
  16. // 聚合缓冲区中值的数据类型
  17. override def bufferSchema: StructType = {
  18. StructType(StructField("sum", IntegerType) :: StructField("count", IntegerType) :: Nil)
  19. }
  20. // UserDefinedAggregateFunction返回值的数据类型。
  21. override def dataType: DataType = DoubleType
  22. // 如果这个函数是确定的,即给定相同的输入,总是返回相同的输出。
  23. override def deterministic: Boolean = true
  24. // 初始化给定的聚合缓冲区,即聚合缓冲区的零值。
  25. override def initialize(buffer: MutableAggregationBuffer): Unit = {
  26. // sum, 总的年龄
  27. buffer(0) = 0
  28. // count, 人数
  29. buffer(1) = 0
  30. }
  31. // 使用来自输入的新输入数据更新给定的聚合缓冲区。
  32. // 每个输入行调用一次。(同一分区)
  33. override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
  34. buffer(0) = buffer.getInt(0) + input.getInt(0) //年龄 叠加
  35. buffer(1) = buffer.getInt(1) + 1 //人数叠加
  36. }
  37. // 合并两个聚合缓冲区并将更新后的缓冲区值存储回buffer1。
  38. // 当我们将两个部分聚合的数据合并在一起时,就会调用这个函数。(多个分区)
  39. override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
  40. buffer1(0) = buffer1.getInt(0) + buffer2.getInt(0) //年龄 叠加
  41. buffer1(1) = buffer1.getInt(1) + buffer2.getInt(1) //人数叠加
  42. }
  43. override def evaluate(buffer: Row): Any = {
  44. buffer.getInt(0).toDouble / buffer.getInt(1)
  45. }
  46. val spark = SparkSession
  47. .builder()
  48. .appName("Spark SQL basic example")
  49. // .config("spark.some.config.option", "some-value")
  50. .master("local[*]") // 本地测试
  51. .getOrCreate()
  52. import spark.implicits._
  53. def main(args: Array[String]): Unit = {
  54. spark.udf.register("myAvg", TestUDAF)
  55. val ds: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
  56. ds.createOrReplaceTempView("table1")
  57. //SQL
  58. spark.sql("select myAvg(age) as avgAge from table1")
  59. .show()
  60. //DSL
  61. val myavg = TestUDAF
  62. ds.select(TestUDAF($"age").as("avgAge"))
  63. .show()
  64. }
  65. }
  66. 输出结果:
  67. +------+
  68. |avgAge|
  69. +------+
  70. | 31.75|
  71. +------+
  72. +------+
  73. |avgAge|
  74. +------+
  75. | 31.75|
  76. +------+

强类型用户自定义聚合函数

通过继承Aggregator(是org.apache.spark.sql.expressions 下的 不要引错包了)

  1. package com.test.spark
  2. import org.apache.spark.sql.{Dataset, Encoder, Encoders, SparkSession}
  3. import org.apache.spark.sql.expressions._
  4. /**
  5. * @author Administrator
  6. * 2019/7/22-16:07
  7. *
  8. */
  9. // 既然是强类型,可能有 case 类
  10. case class Person(name: String, age: Double, ip: String)
  11. case class Average(var sum: Double, var count: Double)
  12. object MyAverage extends Aggregator[Person, Average, Double] {
  13. // 此聚合的值为零。应该满足任意b + 0 = b的性质。
  14. // 定义一个数据结构,保存工资总数和工资总个数,初始都为0
  15. override def zero: Average = {
  16. Average(0, 0)
  17. }
  18. // 将两个值组合起来生成一个新值。为了提高性能,函数可以修改b并返回它,而不是为b构造新的对象。
  19. // 相同 Execute 间的数据合并(同一分区)
  20. override def reduce(b: Average, a: Person): Average = {
  21. b.sum += a.age
  22. b.count += 1
  23. b
  24. }
  25. // 合并两个中间值。
  26. // 聚合不同 Execute 的结果(不同分区)
  27. override def merge(b1: Average, b2: Average): Average = {
  28. b1.sum += b2.sum
  29. b1.count += b2.count
  30. b1
  31. }
  32. // 计算最终结果
  33. override def finish(reduction: Average): Double = {
  34. reduction.sum.toInt / reduction.count
  35. }
  36. // 为中间值类型指定“编码器”。
  37. override def bufferEncoder: Encoder[Average] = Encoders.product
  38. // 为最终输出值类型指定“编码器”。
  39. override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
  40. val spark = SparkSession
  41. .builder()
  42. .appName("Spark SQL basic example")
  43. // .config("spark.some.config.option", "some-value")
  44. .master("local[*]") // 本地测试
  45. .getOrCreate()
  46. import spark.implicits._
  47. def main(args: Array[String]): Unit = {
  48. val ds: Dataset[Person] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson").as[Person]
  49. ds.show()
  50. val avgAge = MyAverage.toColumn/*.name("avgAge")*///指定该列的别名为avgAge
  51. ds.select(avgAge)//执行avgAge.as("columnName") 汇报org.apache.spark.sql.AnalysisException错误 别名只能在上面指定(目前测试是这样)
  52. .show()
  53. }
  54. }
  55. 输出结果:
  56. +---+---------------+---------+
  57. |age| ip| name|
  58. +---+---------------+---------+
  59. | 24| 192.168.0.8| lillcol|
  60. |100| 192.168.255.1| adson|
  61. | 39| 192.143.255.1| wuli|
  62. | 20| 192.168.255.1| gu|
  63. | 15| 243.168.255.9| ason|
  64. | 1| 108.168.255.1| tianba|
  65. | 25|222.168.255.110|clearlove|
  66. | 30|222.168.255.110|clearlove|
  67. +---+---------------+---------+
  68. +------+
  69. |avgAge|
  70. +------+
  71. | 31.75|
  72. +------+

本文为原创文章,转载请注明出处!!!

Spark 自定义函数(udf,udaf)的更多相关文章

  1. 大数据学习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 ...

  2. spark自定义函数之——UDAF使用详解及代码示例

    UDAF简介 UDAF(User Defined Aggregate Function)即用户定义的聚合函数,聚合函数和普通函数的区别是什么呢,普通函数是接受一行输入产生一个输出,聚合函数是接受一组( ...

  3. Hive 自定义函数 UDF UDAF UDTF

    1.UDF:用户定义(普通)函数,只对单行数值产生作用: 继承UDF类,添加方法 evaluate() /** * @function 自定义UDF统计最小值 * @author John * */ ...

  4. Spark(十三)SparkSQL的自定义函数UDF与开窗函数

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

  5. hive自定义函数UDF UDTF UDAF

    Hive 自定义函数 UDF UDTF UDAF 1.UDF:用户定义(普通)函数,只对单行数值产生作用: UDF只能实现一进一出的操作. 定义udf 计算两个数最小值 public class Mi ...

  6. SparkSQL中的自定义函数UDF

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

  7. 10_Hive自定义函数UDF

    Hive官方的UDF手册地址是:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 1.使用内置函数的快捷方法: 创 ...

  8. T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst、语言版本影响!

    原文:T-SQL: 17 个与日期时间相关的自定义函数(UDF),周日作为周的最后一天,均不受 @@DateFirst.语言版本影响! CSDN 的 Blog 太滥了!无时不刻地在坏! 开始抢救性搬家 ...

  9. Hadoop生态圈-Hive的自定义函数之UDAF(User-Defined Aggregation Function)

    Hadoop生态圈-Hive的自定义函数之UDAF(User-Defined Aggregation Function) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.

  10. 三 Hive 数据处理 自定义函数UDF和Transform

    三  Hive 自定义函数UDF和Transform 开篇提示: 快速链接beeline的方式: ./beeline -u jdbc:hive2://hadoop1:10000 -n hadoop 1 ...

随机推荐

  1. bzoj1046题解

    [解题思路] 先倒着求一遍LIS,然后对于每个询问L从左到右找到第一个大于等于L的上升序列即可.复杂度O(N(log2N+M)). [参考代码] #pragma GCC optimize(2) #in ...

  2. spark面试问题收集

    spark面试问题 1.spark中的RDD是什么,有哪些特性 RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可 ...

  3. NX二次开发-Ufun API Example

    UF公共类型 UF_begin_timer计时函数 https://www.cnblogs.com/nxopen2018/p/10957135.html UF_end_timer计时函数 https: ...

  4. CF D. Walking Between Houses (贪心)

    题意: 现在有n个房子排成一列,编号为1~n,起初你在第1个房子里,现在你要进行k次移动,每次移动一都可以从一个房子i移动到另外一个其他的房子j里(i != j),移动的距离为|j - i|.问你进过 ...

  5. eclipse中server name选项变灰

    删除workspace中.metadata\.plugins\org.eclipse.core.runtime\.settings目录下 org.eclipse.wst.server.core.pre ...

  6. PAT_A1048#Find Coins

    Source: PAT A1048 Find Coins (25 分) Description: Eva loves to collect coins from all over the univer ...

  7. node express 会话管理中间件 --- cookie-parser

    本文转载自:https://www.cnblogs.com/bq-med/p/8995100.html cookie是由服务器发送给客户端(浏览器)的小量信息. 我们知道,平时上网时都是使用无状态的H ...

  8. mongodb 数据修改

    update:语法格式如下: db.collection.update( <query>, <update>, { upsert: <boolean>, multi ...

  9. Educational Codeforces Round 56 D - Beautiful Graph

    ​题目大意: 在给定的一个图中(可能不连通) 给每个点赋值1.2.3 使得一条边上的两个端点点权相加为奇数 求方案数 一条满足条件的路径上的点权必为一奇一偶交替 偶数只有2 奇数有1.3 若位于1.3 ...

  10. C语言之文件包含

    c = #include <stdio.h> #include "A.h" int main() { /******************************** ...