Spark-SQL

深入Spark-SQL核心编程:自定义函数与聚合函数实战

  • 在大数据处理领域,Spark-SQL凭借其强大的功能和灵活的操作方式备受青睐。今天,我们就一起深入探索Spark-SQL中的自定义函数和聚合函数,通过实际案例来揭开它们的神秘面纱。
  • 在开发Spark-SQL应用时,首先要在IDEA中创建子模块并添加依赖,引入spark-sql_2.12库,版本选择3.0.0 ,这就为后续的开发搭建好了基础环境。
  • 自定义函数中,UDF(User-Defined Function)是一种非常实用的工具。假设我们有一个包含用户信息的JSON文件,里面有用户名和年龄等字段。通过创建SparkSession读取这个文件后,我们可以使用UDF来对用户名进行处理。比如,想在每个用户名前加上"Name:",代码如下:
  • val sparkConf = new SparkConf().setMaster("local\*").setAppName("SQLDemo")
  • val spark = SparkSession.builder().config(sparkConf).getOrCreate()
  • import spark.implicits._
  • val df = spark.read.json("Spark-SQL/input/user.json")
  • spark.udf.register("addName",(x:String)=>"Name:"+x)
  • df.createOrReplaceTempView("people")
  • spark.sql("select addName(username),age from people").show()
  • spark.stop()
  • 这段代码中,spark.udf.register注册了一个名为addName的UDF,它接收一个字符串类型的用户名,返回添加前缀后的新字符串。之后通过SQL语句调用这个UDF,就能得到想要的结果。
  • 接下来看看自定义聚合函数。假设计算员工的平均工资,有多种实现方式。
  • 使用RDD的方式比较直观,先将数据转换为RDD,再通过map和reduce操作进行计算:
  • val sparkconf = new SparkConf().setAppName("app").setMaster("local\*")
  • val sc = new SparkContext(conf)
  • val resRDD = sc.makeRDD(List(("zhangsan", 20), ("lisi", 30), ("wangwu",40))).map {
  • case (name, salary) => (salary, 1)
  • }.reduce {
  • (t1, t2) => (t1._1 + t2._1, t1._2 + t2._2)
  • println(resRDD._1/resRDD._2)
  • sc.stop()
  • 在Spark 3.0之前,弱类型UDAF(User-Defined Aggregate Function)可以实现自定义聚合。要计算平均工资,需要定义一个类继承UserDefinedAggregateFunction,并实现它的多个方法,如inputSchema定义输入数据的结构,bufferSchema定义缓冲区数据结构等。之后注册这个UDAF,在SQL语句中调用:
  • class MyAverageUDAF extends UserDefinedAggregateFunction{
  • // 省略具体实现方法
  • }
  • val sparkconf = new SparkConf().setAppName("app").setMaster("local\*")
  • val spark = SparkSession.builder().config(conf).getOrCreate()
  • import spark.implicits._
  • val res = spark.sparkContext.makeRDD(List(("zhangsan", 20), ("lisi", 30), ("wangwu",40)))
  • val df = res.toDF("name","salary")
  • df.createOrReplaceTempView("user")
  • var myAverage = new MyAverageUDAF
  • spark.udf.register("avgSalary",myAverage)
  • spark.sql("select avgSalary(salary) from user").show()
  • spark.stop()
  • 从Spark 3.0开始,强类型UDAF(Aggregator)使用起来更加方便。同样以计算平均工资为例,先定义一个用于存储中间结果的样例类,再创建继承Aggregator的类,实现相关方法:
  • case class Buff(var sum:Long,var cnt:Long)
  • class MyAverageUDAF extends AggregatorLong,Buff,Double{
  • // 省略具体实现方法
  • }
  • val sparkconf = new SparkConf().setAppName("app").setMaster("local\*")
  • val spark = SparkSession.builder().config(conf).getOrCreate()
  • import spark.implicits._
  • val res = spark.sparkContext.makeRDD(List(("zhangsan", 20), ("lisi", 30), ("wangwu",40)))
  • val df = res.toDF("name","salary")
  • df.createOrReplaceTempView("user")
  • var myAverage = new MyAverageUDAF
  • spark.udf.register("avgSalary",functions.udaf(myAverage))
  • spark.sql("select avgSalary(salary) from user").show()
  • spark.stop()
  • 通过这些不同方式的实践,我们能更灵活地运用Spark-SQL进行数据处理,根据实际需求选择最合适的方法,提升大数据处理的效率和效果。希望大家在实践中不断探索,掌握更多Spark-SQL的技巧。
相关推荐
Zhao-Jichao4 分钟前
AI Prompting for Everyone 课程笔记 - P08 上下文 Context
人工智能·笔记
鬼手点金8 分钟前
Skills:领域能力的可组合单元
java·人工智能·笔记·自动化·1024程序员节
夕除9 小时前
Redis 过期策略
redis·笔记·面试
Nuanyt11 小时前
Agent 学习笔记(下篇三):上线工程、进阶选择与操作界面(Stage 7 / 7.5 / 8 + 延伸路线)
笔记·python·学习·memory·aiagent·harness
叼烟扛炮12 小时前
Linux 学习笔记(四十一):TCP 并发演进——从单进程到多线程服务器
linux·运维·服务器·网络·笔记·学习·tcp/ip
叼烟扛炮13 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
songyuc13 小时前
【Manskill3】TableSceneBuilder学习笔记
pytorch·笔记·学习
゛凌乱的记忆づ15 小时前
好用的md文件编辑器——TyporaS与Typora
笔记·git·typora·markdown
zroooo16 小时前
计算机学习-知识庞大而繁杂
笔记·学习
坤坤子吖16 小时前
算法学习——单调队列
开发语言·c++·笔记·学习·算法