文章目录


一、UDF自定义函数

  • 如图所示是function中的主要类别:
  • 【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部

  • UDF(User Defined Function):spark SQL中用户自定义函数,用法和spark SQL中的内置函数类似;是saprk SQL中内置函数无法满足要求,用户根据业务需求自定义的函数

定义数据集:

val source = Seq(
("Thin", "Cell phone", 6000),
("Normal", "Tablet", 5500),
("Very thin", "Cell phone", 5500),
("Pro", "Tablet", 3000),
("Pro 20", "Cell phone", 2500),
("Foldable", "Tablet", 3500),
("Mini", "Cell phone", 5500),
("Ultra thin", "Cell phone", 4500)
).toDF("product", "category", "revenue")
source.show()
import spark.implicits._
import org.apache.spark.sql.functions._

需求一:聚合每个类别的总价 ---- sum()

//需求一:聚合每个类别的总价
val rev_sum = source.groupBy('category)
.agg(sum("revenue") as "sum")
rev_sum.show()

【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_02


返回顶部


需求二:把名称变为小写 ---- lower()

// 需求二:把名称变为小写
val lower_name = source.select(lower('product),'category,'revenue)
lower_name.show()

【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部_03


返回顶部


需求三:把价格转为字符串的形式 ---- toStr(revenue:Long)

def toStr(revenue:Long):String = {
(revenue/1000)+"K"
}
// 需求三:把价格变为字符串的形式
val toStrUdf = udf(toStr _)
source.select('product,'category,toStrUdf('revenue) as "revenue")
.show()

【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部_04


返回顶部


二、窗口函数 Window

窗口函数类似于oracle中的分析函数

  • 聚合函数:---- 所有的聚合函数
  • 排名函数:rank()、dense_rank()、row_number()
  • 分析函数:first_value()、last_value()、lag()、lead()

需求:得到分类后排名前2的记录

【SparkSQL】扩展 ---- 函数(UDF、窗口)_sql_05

方案一:使用常见语法子查询

【SparkSQL】扩展 ---- 函数(UDF、窗口)_sql_06


通过这种方法查询出来的数据只是总数据的前两条记录。

返回顶部


方案二:使用窗口函数

【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_07

// 定义数据集
val source = Seq(
("Thin", "Cell phone", 6000),
("Normal", "Tablet", 5500),
("Very thin", "Cell phone", 5500),
("Pro", "Tablet", 3000),
("Pro 20", "Cell phone", 2500),
("Foldable", "Tablet", 3500),
("Mini", "Cell phone", 5500),
("Ultra thin", "Cell phone", 4500)
).toDF("product", "category", "revenue")

// 需求:取出每个商品分类中最贵的两个商品
// 1.定义窗口(函数)
val window = Window.partitionBy('category)
.orderBy('revenue desc)
// 2.处理
import org.apache.spark.sql.functions._
source.select('product,'category,dense_rank() over(window) as "rank" )
.where('rank <=2)
.show()

SQL:

source.createOrReplaceTempView("goods")
spark.sql(
"select product,category,revenue " +
"from (select *,dense_rank() over (partition by category order by revenue desc) as rank from goods) " +
"where rank<=2")
.show()

【SparkSQL】扩展 ---- 函数(UDF、窗口)_窗口函数_08

返回顶部


解析

【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_09


【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部_10


返回顶部


partition的定义

控制哪些行会被放在一起,同时这个定义也就类似于Shuffle,会将同一个分组的数据放在同一台机器中处理


【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部_11


返回顶部


order的定义

在一个分组内进行排序,因为很多操作,如rank、dense_rank等都需要进行排序


【SparkSQL】扩展 ---- 函数(UDF、窗口)_sql_12


返回顶部


Frame定义

【SparkSQL】扩展 ---- 函数(UDF、窗口)_sql_13


Frame控制方式

【SparkSQL】扩展 ---- 函数(UDF、窗口)_窗口函数_14


【SparkSQL】扩展 ---- 函数(UDF、窗口)_返回顶部_15


返回顶部


函数部分

【SparkSQL】扩展 ---- 函数(UDF、窗口)_窗口函数_16


【SparkSQL】扩展 ---- 函数(UDF、窗口)_sql_17


【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_18


返回顶部


案例:统计每个商品与同类最贵商品的差值

import org.apache.spark.sql.functions._
// 定义数据集
val source = Seq(
("Thin", "Cell phone", 6000),
("Normal", "Tablet", 5500),
("Very thin", "Cell phone", 5500),
("Pro", "Tablet", 3000),
("Pro 20", "Cell phone", 2500),
("Foldable", "Tablet", 3500),
("Mini", "Cell phone", 5500),
("Ultra thin", "Cell phone", 4500)
).toDF("product", "category", "revenue")

// 定义窗口
val window = Window.partitionBy("category")
.orderBy($"revenue".desc)
// 通过窗口找出每个类别商品的最大值
val max_price = max("revenue") over(window)
val max_gap = source.select('product,'category,'revenue,(max_price-'revenue) as "max_gap")
max_gap.show()

【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_19

返回顶部


总结

【SparkSQL】扩展 ---- 函数(UDF、窗口)_spark_20

窗口函数和GroupBy最大的区别,就是GroupBy的聚合对每一个组只有一个结果,而窗口函数可以对每一条数据都有一个结果。也就是说,窗口函数其实就是根据当前数据,计算它在所在的组中的统计数据。