【Spark】(九)Spark SQL函数(内置函数、自定义函数)

本文详细介绍了Spark SQL中的内置函数,包括聚合、集合、日期时间、数学、混合、字符串和窗口函数,并提供了使用示例。同时,讲解了自定义函数(UDF、UDAF、UDTF)的创建、注册与调用,以及它们在数据处理中的应用,帮助理解Spark SQL函数的全面功能。

内置函数(org.apache.spark.sql.funtions.scala)

一、常用内置函数:

在这里插入图片描述
1.聚合函数
approx_count_distinct/countDistinct: 计算某一列或几列不同元素的个数
avg: 平均数, count: 个数;
first: 首个元素, last:最后一个元素;
max/min, mean, sum, sumDistinct
var_pop: 总体方差, var_samp/variance 计算样本方差; stddev_pop, stddev_samp: 标准差
covar_pop, covar_samp 协方差,.corr 相关系数
kurtosis: 峰度; .skewness:偏度

2.集合函数
array_contains: 包含某个元素
array_distinct: 删除重复的元素
array_except 返回一个array 在第一个col 不在第二个col的元素
array_intersect(col1, col2) 交集4
array_max, array_min, array_position(col, value):第一次出现value的位置,从1开始
array_remove(col, element) 删除出现的元素
array_repeat(col, count): 创造一个数组,count为重复的个数
array_sort(col): 对数组进行排序
array_union(col1, col2), 合并操作
array_overlap, 判断是否有重叠
array_zip, 合并,类似于python的zip
reverse: 逆序; shuffle: 打乱; size, slice, sort_array

3.日期/时间函数
日期时间转换
unix_timestamp, from_unixtime, to_date, quarter, day, dayofyear, weekofyear, from_utc_timestamp, to_utc_timestamp
从日期时间中提取字段
year, month, dayofmonth, hour, minute, second
日期/时间计算
datediff, date_add, date_sub, add_months, last_day, next_day, months_between
获取当前时间等
current_date, current_timestamp, trunc, date_format

4.数学函数
abs, acros, asin, atan, atan2, bin, cbrt, ceil, conv, cos, sosh, exp, expm1, factorial, floor, hex, hypot, log, log10, log1p, log2, pmod, pow, rint, round, shiftLeft, shiftRight, shiftRightUnsigned, signum, sin, sinh, sqrt, tan, tanh, toDegrees, toRadians, unhex

5.混合函数
array, bitwiseNOT, callUDF, coalesce, crc32, greatest, if, inputFileName, isNaN, isnotnull, isnull, least, lit, md5, monotonicallyIncreasingId, nanvl, negate, not, rand, randn, sha, sha1, sparkPartitionId, struct, when

6.字符串函数
字符串分割,大小写转化,删除首尾空白, 正则表达式匹配
ltrim, rtrim, trim
ascii, base64, unbase64, decode, encode, format_string
repeat, reverse
instr(str, substr): 第一次出现的位置; locate(substr, str, pos=1)
字符拼接:concat, concat_ws
分割,子串: split, substring, substring_index
isnan, isnull, nanvl(col1, col2): 返回col1, 如果col1不为nan, 否则返回col2
lower, upper

7.窗口函数
cumeDist, denseRank, lag, lead, ntile, percentRank, rank, rowNumber
作用:分组,对一个组执行函数,这里面最常用的函数是rowNumber,我们可以用它来分组取topN

二、内置函数的使用

案例一:

object InnerFunctionDemo {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("InnerFunctionDemo").master("local[*]").getOrCreate()

    import spark.implicits._
    val sc = spark.sparkContext

    //模拟用户访问日志信息
    val accessLog = Array(
      "2016-12-27,001",
      "2016-12-27,001",
      "2016-12-27,002",
      "2016-12-28,003",
      "2016-12-28,004",
      "2016-12-28,002",
      "2016-12-28,002",
      "2016-12-28,001"
    )

    //定义DataFrame的结构
    val schema = StructType(Array(
      StructField("day", StringType),
      StructField("userId", IntegerType, true)
    ))

    //根据集合数据生成RDD
    val rdd = sc.parallelize(accessLog).map(x => x.split(",")).map(x => Row(x(0), x(1).toInt))

    //根据数据以及Schema信息生成DataFrame
    val df = spark.createDataFrame(rdd,schema)
    df.printSchema()
    df.show()

    //导入Spark SQL内置的函数
    import org.apache.spark.sql.functions._

    //求每天所有的访问量(pv)
    df.groupBy(df("day")).agg(count(df("userId")).as("pv")).show()

    //求每天的去重访问量(uv)
    df.groupBy(df("day")).agg(countDistinct(df("userId")).alias("v")).show()
  }
}

在这里插入图片描述
在这里插入图片描述
案例二:

object InnerFunctionDemo2 {
  case class Student(id: Int, name: String, gender: String, age: Int)

  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("InnerFunctionDemo2").master("local[*]").getOrCreate()

    val sc = spark.sparkContext
    import spark.implicits._

    val stuDF: DataFrame = Seq(
      Student(1001, "zhangsan", "F", 20),
      Student(1002, "lisi", "M", 16),
      Student(1003, "wangwu", "M", 21),
      Student(1004, "zhaoliu", "F", 21),
      Student(1005, "zhouqi", "M", 22),
      Student(1006, "qianba", "M", 19),
      Student(1007, "liuliu", "F", 23)
    ).toDF()
    stuDF.printSchema()
    stuDF.show()

    //导入Spark SQL内置的函数
    import org.apache.spark.sql.functions._
    stuDF.groupBy(stuDF("gender")).agg(count(stuDF("id"))).show()
    stuDF.groupBy(stuDF("gender")).agg(max(stuDF("age"))).show()
    stuDF.groupBy(stuDF("gender")).agg(min(stuDF("age"))).show()

    stuDF.groupBy(stuDF("gender")).agg("age"->"max","age"->"min","age"->"avg","id"->"count").show()

    // select * from table group by gender,age
    stuDF.groupBy("gender","age").count().show()
  }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义函数

步骤

1、定义函数
2、注册函数
SparkSession.udf.register():只在sql()中有效
functions.udf():对DataFrame API均有效
3、函数调用

案例

需求:用户行为喜好个数统计
输入数据格式:
在这里插入图片描述
输出数据格式:
在这里插入图片描述
创建一个hobbies.txt文件

alice   jogging,Coding,cooking
lina   travel,dance

代码实现

object SparkUDFDemo {

  case class Hobbies(name:String,hobbies:String)

  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("SparkUDFDemo").master("local[*]").getOrCreate()

    //需要手动导入一个隐式转换,否则RDD无法转换成DF
    import spark.implicits._
    val sc = spark.sparkContext

    val rdd = sc.textFile("in/hobbies.txt")
    val df = rdd.map(x=>x.split("\t")).map(x=> Hobbies(x(0),x(1))).toDF()
    df.printSchema()
    df.show()

    df.registerTempTable("hobbies")
    //注册自定义函数,注意是匿名函数
    spark.udf.register("hobby_num", (v:String) => v.split(",").size)

    val frame = spark.sql("select name,hobbies,hobby_num(hobbies) as hobnum from hobbies")
    frame.show()
  }
}

在这里插入图片描述

补充内容:(udf,udaf,udtf之间的区别)

1、UDF:用户定义(普通)函数,只对单行数值产生作用;

继承UDF类,添加方法 evaluate()

/**
     * @function 自定义UDF统计最小值
     * @author John
     *
     */
    public class Min extends UDF {
        public Double evaluate(Double a, Double b) {
            if (a == null)
                a = 0.0;
            if (b == null)
                b = 0.0;
            if (a >= b) {
                return b;
            } else {
                return a;
            }
        }
    }

2、UDAF:User- Defined Aggregation Funcation;用户定义聚合函数,可对多行数据产生作用;等同与SQL中常用的SUM(),AVG(),也是聚合函数;

聚合函数使用:

SELECT store_name, SUM(sales)
FROM Store_Information
GROUP BY store_name
HAVING SUM(sales) > 1500
ORDER BY SUM(sales);
键字HAVING总要放在GROUP BY之后,ORDER BY之前

UDAF实现有简单与通用两种方式:

  • a. 简单UDAF因为使用Java反射导致性能损失,而且有些特性不能使用,已经被弃用了;
  • b. 另一种涉及两个类:AbstractGenericUDAFResolver、GenericUDAFEvaluator;
    继承UDAFResolver类,重写 getEvaluator() 方法;
    继承GenericUDAFEvaluator类,生成实例给getEvaluator();
    在GenericUDAFEvaluator类中,重写init()、iterate()、terminatePartial()、merge()、terminate()方法

参考:
hive udaf开发入门和运行过程详解
Hive UDAF开发详解

3.UDTF:User-Defined Table-Generating Functions,用户定义表生成函数,用来解决输入一行输出多行;

继承GenericUDTF类,重写initialize(返回输出行信息:列个数,类型), process, close三方法;
参考:
hive中UDTF编写和使用
hive0.13的udtf使用例子

4、其它

删除临时函数 drop temporary function toUpper;

转载至:udf,udaf,udtf之间的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值