spark SQL (二) 聚合
聚合内置功能DataFrames提供共同聚合,例如count()
,countDistinct()
,avg()
,max()
,min()
,等。虽然这些功能是专为DataFrames,spark
SQL还拥有类型安全的版本,在其中的一些 scala 和 Java使用强类型数据集的工作。而且,用户可以预定义的聚合函数,也可以创建自己自定义的聚合函数。
1, 非类型化的用户定义的聚合函数
用户必须扩展UserDefinedAggregateFunction 抽象类来实现自定义的非类型集合函数。例如,用户定义的平均值可能如下所示:
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.expressions.MutableAggregationBuffer
import org.apache.spark.sql.expressions.UserDefinedAggregateFunction
import org.apache.spark.sql.types._
object UserDefinedUntypedAggregation {
object MyAverage extends UserDefinedAggregateFunction {
// 这集合函数的输入参数的数据类型
def inputSchema: StructType = StructType(StructField("inputColumn", LongType) :: Nil)
// 在聚合缓冲区中的值的数据类型
def bufferSchema: StructType = {
StructType(StructField("sum", LongType) :: StructField("count", LongType) :: Nil)
}
// 返回值的数据类型
def dataType: DataType = DoubleType
// 此函数是否始终在相同的输入上返回相同的输出
def deterministic: Boolean = true
// 初始化给定的聚合缓冲区。缓冲区本身就是一个“Row”,除了
// 像标准方法(例如,get(),getBoolean())检索值之外,还提供
// 更新其值的机会。请注意,缓冲区内的数组和映射仍然是
// 不可变的。
def initialize(buffer: MutableAggregationBuffer): Unit = {
buffer(0) = 0L
buffer(1) = 0L
}
// 更新给定聚合缓冲区`与来自新的输入数据buffer``input`
def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
if (!input.isNullAt(0)) {
buffer(0) = buffer.getLong(0) + input.getLong(0)
buffer(1) = buffer.getLong(1) + 1
}
}
// 合并两个聚合缓冲剂和存储更新的缓冲器值回`buffer1`
def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
buffer1(0) = buffer1.getLong(0) + buffer2.getLong(0)
buffer1(1) = buffer1.getLong(1) + buffer2.getLong(1)
}
// 计算最终结果
def evaluate(buffer: Row): Double = buffer.getLong(0).toDouble / buffer.getLong(1)
}
def main(args: Array[String]): Unit = {
val spark = SparkSession
.builder()
.appName("Spark SQL user-defined DataFrames aggregation example")
.getOrCreate()
// 注册函数来访问
spark.udf.register("myAverage", MyAverage)
val df = spark.read.json("employees.json")
df.createOrReplaceTempView("employees")
df.show()
// +-------+------+
// | name|salary|
// +-------+------+
// |Michael| 3000|
// | Andy| 4500|
// | Justin| 3500|
// | Berta| 4000|
// +-------+------+
val result = spark.sql("SELECT myAverage(salary) as average_salary FROM employees")
result.show()
// +--------------+
// |average_salary|
// +--------------+
// | 3750.0|
// +--------------+
spark.stop()
}
}
2,类型安全的用户定义的聚合函数
用于强类型数据集的用户定义聚合围绕着Aggregator抽象类。例如,类型安全的用户定义的平均值可能如下所示:
import org.apache.spark.sql.{Encoder, Encoders, SparkSession}
import org.apache.spark.sql.expressions.Aggregator
object UserDefinedTypedAggregation {
case class Employee(name: String, salary: Long)
case class Average(var sum: Long, var count: Long)
object MyAverage extends Aggregator[Employee, Average, Double] {
// 这个聚合的零值。应满足以下性质:b + zero = b
def zero: Average = Average(0L, 0L)
//合并两个值产生一个新的值。为了性能,函数可以修改`buffer`
//并返回它,而不是构造一个新的对象
def reduce(buffer: Average, employee: Employee): Average = {
buffer.sum += employee.salary
buffer.count += 1
buffer
}
// 合并两个中间值
def merge(b1: Average, b2: Average): Average = {
b1.sum += b2.sum
b1.count += b2.count
b1
}
// 变换还原的输出
def finish(reduction: Average): Double = reduction.sum.toDouble / reduction.count
// 指定中间值类型的
def bufferEncoder: Encoder[Average] = Encoders.product
// 指定最终输出值类型的
def outputEncoder: Encoder[Double] = Encoders.scalaDouble
}
// $example off:typed_custom_aggregation$
def main(args: Array[String]): Unit = {
val spark = SparkSession
.builder()
.appName("Spark SQL user-defined Datasets aggregation example")
.getOrCreate()
import spark.implicits._
val ds = spark.read.json("examples/src/main/resources/employees.json").as[Employee]
ds.show()
// +-------+------+
// | name|salary|
// +-------+------+
// |Michael| 3000|
// | Andy| 4500|
// | Justin| 3500|
// | Berta| 4000|
// +-------+------+
//将函数转换为“TypedColumn”,并给它一个名称
val averageSalary = MyAverage.toColumn.name("average_salary")
val result = ds.select(averageSalary)
result.show()
// +--------------+
// |average_salary|
// +--------------+
// | 3750.0|
// +--------------+
spark.stop()
}
}
spark SQL (二) 聚合的更多相关文章
- 理解Spark SQL(二)—— SQLContext和HiveContext
使用Spark SQL,除了使用之前介绍的方法,实际上还可以使用SQLContext或者HiveContext通过编程的方式实现.前者支持SQL语法解析器(SQL-92语法),后者支持SQL语法解析器 ...
- 6. Spark SQL和Beeline
*以下内容由<Spark快速大数据分析>整理所得. 读书笔记的第六部分是讲的是Spark SQL和Beeline. Spark SQL是Spark用来操作结构化和半结构化数据的接口. 一. ...
- Spark学习之路(十一)—— Spark SQL 聚合函数 Aggregations
一.简单聚合 1.1 数据准备 // 需要导入spark sql内置的函数包 import org.apache.spark.sql.functions._ val spark = SparkSess ...
- Spark 系列(十一)—— Spark SQL 聚合函数 Aggregations
一.简单聚合 1.1 数据准备 // 需要导入 spark sql 内置的函数包 import org.apache.spark.sql.functions._ val spark = SparkSe ...
- Spark SQL概念学习系列之为什么使用 Spark SQL?(二)
简单地说,Shark 的下一代技术 是Spark SQL. 由于 Shark 底层依赖于 Hive,这个架构的优势是对传统 Hive 用户可以将 Shark 无缝集成进现有系统运行查询负载. 但是也看 ...
- Spark SQL 用户自定义函数UDF、用户自定义聚合函数UDAF 教程(Java踩坑教学版)
在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...
- 《Spark Python API 官方文档中文版》 之 pyspark.sql (二)
摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...
- 二、spark SQL交互scala操作示例
一.安装spark spark SQL是spark的一个功能模块,所以我们事先要安装配置spark,参考: https://www.cnblogs.com/lay2017/p/10006935.htm ...
- Spark SQL之External DataSource外部数据源(二)源代码分析
上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External Da ...
随机推荐
- “You may need an appropriate loader to handle this file type”
这里不能为空!!!!!!!!!!!!!!!!!!!!
- Linux常用命令 | grep
作者简介 李先生(Lemon),高级运维工程师(自称),SRE专家(目标),梦想在35岁买一辆保时捷.喜欢钻研底层技术,认为底层基础才是王道.一切新技术都离不开操作系统(CPU.内存.磁盘).网络 ...
- Nginx+FFmpeg实现RTSP转RTMP
RTSP转RTMP 本次转流采用Centos+Nginx+FFmpeg实现,具体实现如下: 1. 安装Ngxin 安装详细略(可以选择安装阿里的Tengine,官方[下载路径](Download - ...
- leetcode 940. 不同的子序列 II (动态规划 ,字符串, hash,好题)
题目链接 https://leetcode-cn.com/problems/distinct-subsequences-ii/ 题意: 给定一个字符串,判断里面不相同的子串的总个数 思路: 非常巧妙的 ...
- 记一次centos7重启后docker无法启动的问题
问题描述 在重新了centos7系统后,docker突然就启动不了了,查看报错信息 [root@localhost ~]# systemctl status docker.service ● dock ...
- Flask+pin
Flask+SSTI的新火花 记一次buu刷题记和回顾祥云杯被虐出屎的经历.题目:[GYCTF2020]FlaskApp 一 题目初见 朴实无华的页面,一个base64的小程序页面 看到有提示. 我就 ...
- Mybatis执行流程学习之手写mybatis雏形
Mybatis是目前开发中最常用的一款基于ORM思想的半自动持久层框架,平时我们都仅仅停留在使用阶段,对mybatis是怎样运行的并不清楚,今天抽空找到一些资料自学了一波,自己写了一个mybatis的 ...
- [Usaco2008 Open]Roads Around The Farm分岔路口
题目描述 约翰的N(1≤N≤1,000,000,000)只奶牛要出发去探索牧场四周的土地.她们将沿着一条路走,一直走到三岔路口(可以认为所有的路口都是这样的).这时候,这一群奶牛可能会分成两群,分别沿 ...
- [Usaco2007 Jan]Telephone Lines架设电话线
题目描述 FarmerJohn打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务.于是,FJ必须为此向电信公司支付一定的费用.FJ的农场周围分布着N(1<=N<=1,000)根 ...
- 与图论的邂逅05:最近公共祖先LCA
什么是LCA? 祖先链 对于一棵树T,若它的根节点是r,对于任意一个树上的节点x,从r走到x的路径是唯一的(显然),那么这条路径上的点都是并且只有这些点是x的祖先.这些点组成的链(或者说路径)就是x的 ...