【Sparksql学习】SparkSql常用函数(DSL+scala)

SparkSQL 常用函数(Scala DSL 风格)全总结

SparkSQL 的 DSL(Domain-Specific Language)风格基于 DataFrame/Dataset API 调用函数,无需编写 SQL 字符串,更贴合 Scala 编程习惯。以下按功能分类梳理高频函数,所有函数均需导入 org.apache.spark.sql.functions._(核心包),示例基于 Scala 语法,结合实际业务场景说明。

前置说明

  • 示例中统一使用 df: DataFrame 代表待操作的数据集;
  • 函数调用格式为 df.withColumn("新列名", 函数名(参数))(新增列)或 df.select(函数名(列名), ...)(查询列);
  • 列名可用 col("列名")$"列名"(需导入 spark.implicits._),示例中混用两种风格以适配不同习惯。

一、基础类型函数

1. 数值函数(处理整数/浮点数)

函数 功能说明 示例(Scala DSL)
abs(col) 绝对值 df.withColumn("abs_num", abs($"num"))
round(col, n) 四舍五入到 n 位小数 df.withColumn("round_num", round($"num", 2))
ceil(col) 向上取整 df.withColumn("ceil_num", ceil($"num"))
floor(col) 向下取整 df.withColumn("floor_num", floor($"num"))
rand() 生成 0~1 随机数(可传种子) df.withColumn("rand_num", rand(123))
pow(col, n) 求 col 的 n 次方 df.withColumn("pow_num", pow($"num", 2))
sqrt(col) 平方根(非负) df.withColumn("sqrt_num", sqrt($"num"))
sum(col) 聚合:求和 df.agg(sum($"num").alias("sum_num"))
avg(col) 聚合:平均值 df.agg(avg($"num").alias("avg_num"))
max/min(col) 聚合:最大值/最小值 df.agg(max($"num"), min($"num"))
count(col) 聚合:非空值计数(count(*) 用 count(lit(1))) df.agg(count($"num").alias("cnt"))
countDistinct(col) 聚合:去重计数 df.agg(countDistinct($"num").alias("distinct_cnt"))

2. 字符串函数

函数 功能说明 示例(Scala DSL)
concat(col1, col2) 拼接字符串 df.withColumn("concat_str", concat($"name", $"age"))
concat_ws(sep, cols) 按分隔符拼接(自动跳过 null) df.withColumn("concat_ws_str", concat_ws("-", $"name", $"age"))
substring(col, start, len) 截取子串(start 从 1 开始) df.withColumn("sub_str", substring($"name", 1, 3))
upper/lower(col) 转大写/小写 df.withColumn("upper_str", upper($"name"))
trim(col) 去除首尾空格(ltrim/rtrim 单侧) df.withColumn("trim_str", trim($"name"))
length(col) 字符串长度 df.withColumn("len_str", length($"name"))
regexp_replace(col, pat, rep) 正则替换 df.withColumn("reg_str", regexp_replace($"phone", "(\\d{3})\\d{4}(\\d{4})", "$1****$2"))
like(col, pat) 模糊匹配(% 任意字符,_ 单个字符) df.filter($"name".like("张%"))
split(col, sep) 按分隔符切分字符串为数组 df.withColumn("split_arr", split($"tags", ","))
instr(col, substr) 查找子串位置(从 1 开始,无则返回 0) df.withColumn("pos", instr($"name", "小"))

3. 日期时间函数

函数 功能说明 示例(Scala DSL)
current_date() 当前日期(yyyy-MM-dd) df.withColumn("now_date", current_date())
current_timestamp() 当前时间戳(yyyy-MM-dd HH:mm:ss) df.withColumn("now_ts", current_timestamp())
to_date(col, fmt) 字符串转日期(指定格式) df.withColumn("date", to_date($"date_str", "yyyyMMdd"))
to_timestamp(col, fmt) 字符串转时间戳 df.withColumn("ts", to_timestamp($"ts_str", "yyyy-MM-dd HH:mm"))
date_format(col, fmt) 日期转指定格式字符串 df.withColumn("date_fmt", date_format($"date", "yyyy年MM月dd日"))
datediff(end, start) 两个日期差值(end - start,单位天) df.withColumn("diff_days", datediff($"end_date", $"start_date"))
date_add/date_sub(col, n) 日期加/减 n 天 df.withColumn("add_days", date_add($"date", 7))
months_between(end, start) 两个日期月份差(小数) df.withColumn("diff_mon", months_between($"end_date", $"start_date"))
add_months(col, n) 日期加 n 个月 df.withColumn("add_mon", add_months($"date", 1))
year/month/day(col) 提取日期的年/月/日 df.withColumn("year", year($"date"))
hour/minute/second(col) 提取时间戳的时/分/秒 df.withColumn("hour", hour($"ts"))
dayofweek(col) 星期几(1=周日,2=周一...7=周六) df.withColumn("weekday", dayofweek($"date"))
dayofyear(col) 一年中的第几天 df.withColumn("day_of_year", dayofyear($"date"))
trunc(col, fmt) 日期截断(fmt:year/month/week 等) df.withColumn("trunc_year", trunc($"date", "year")) // 截断到年初

二、集合函数(数组/Map)

函数 功能说明 示例(Scala DSL)
array(col1, col2, ...) 创建数组 df.withColumn("arr", array($"col1", $"col2"))
array_contains(col, val) 判断数组是否包含指定值 df.filter(array_contains($"tags_arr", "java"))
size(col) 数组/Map 长度 df.withColumn("arr_len", size($"tags_arr"))
explode(col) 炸裂数组(一行转多行) df.select($"name", explode($"tags_arr").alias("tag"))
explode_outer(col) 炸裂数组(保留 null 行) df.select($"name", explode_outer($"tags_arr").alias("tag"))
map(key1, val1, key2, val2) 创建 Map 类型 df.withColumn("map_col", map($"k1", $"v1", $"k2", $"v2"))
map_keys(col) 提取 Map 的所有 key 为数组 df.withColumn("map_keys", map_keys($"map_col"))
map_values(col) 提取 Map 的所有 value 为数组 df.withColumn("map_vals", map_values($"map_col"))
element_at(col, idx/key) 获取数组指定索引元素/Map 指定 key 的值 df.withColumn("arr_elem", element_at($"tags_arr", 1))
concat_ws(sep, col) 数组转字符串(按分隔符拼接) df.withColumn("arr_str", concat_ws(",", $"tags_arr"))

三、条件判断函数

函数 功能说明 示例(Scala DSL)
when(cond, val).otherwise(val) 单条件判断(if-else) df.withColumn("grade", when($"score" >= 90, "A").otherwise("B"))
case_when(cond1 -> val1, cond2 -> val2, ...) 多条件判断(switch) df.withColumn("level", case_when($"score" >= 90 -> "优", $"score" >= 80 -> "良", lit(true) -> "差"))
coalesce(col1, col2, ...) 返回第一个非 null 值 df.withColumn("new_col", coalesce($"col1", $"col2", lit(0)))
isNull/isNotNull(col) 判断列是否为 null/非 null df.filter($"name".isNotNull)
isnan(col) 判断数值是否为 NaN df.filter(isnan($"num"))
nullif(col1, col2) 若 col1=col2 则返回 null,否则返回 col1 df.withColumn("null_col", nullif($"col1", $"col2"))

四、聚合函数(分组/全局)

1. 基础聚合(需配合 groupByagg

函数 功能说明 示例(Scala DSL)
sum(col) 求和 df.groupBy($"dept").agg(sum($"salary").alias("total_sal"))
avg(col) 平均值 df.groupBy($"dept").agg(avg($"salary").alias("avg_sal"))
max/min(col) 最大/最小值 df.groupBy($"dept").agg(max($"salary"), min($"salary"))
count(col) 非空计数 df.groupBy($"dept").agg(count($"id").alias("emp_cnt"))
countDistinct(col) 去重计数 df.groupBy($"dept").agg(countDistinct($"job").alias("job_cnt"))
first/last(col) 分组内第一条/最后一条值 df.groupBy($"dept").agg(first($"name").alias("first_emp"))

2. 高级聚合

函数 功能说明 示例(Scala DSL)
collect_list(col) 分组内收集值为数组(保留重复) df.groupBy($"dept").agg(collect_list($"name").alias("emp_list"))
collect_set(col) 分组内收集值为数组(去重) df.groupBy($"dept").agg(collect_set($"job").alias("job_set"))
sum_distinct(col) 去重后求和 df.agg(sum_distinct($"num").alias("sum_dist"))
agg(Map(col1 -> func1, col2 -> func2)) 批量聚合 df.groupBy($"dept").agg(Map("salary" -> "sum", "age" -> "avg"))

五、窗口函数(开窗函数)

需先定义窗口规范(Window 类,导入 org.apache.spark.sql.expressions.Window),再结合聚合/排名函数使用。

1. 窗口规范定义

scala 复制代码
// 按 dept 分区,按 salary 降序排序
val windowSpec = Window.partitionBy($"dept").orderBy($"salary".desc)
// 按 dept 分区,取当前行前后 1 行(行范围)
val windowSpecWithRange = Window.partitionBy($"dept").orderBy($"salary").rowsBetween(-1, 1)

2. 常用窗口函数

函数 功能说明 示例(Scala DSL)
row_number().over(window) 分区内行号(连续,不重复) df.withColumn("rn", row_number().over(windowSpec))
rank().over(window) 排名(跳号,如 1,2,2,4) df.withColumn("rk", rank().over(windowSpec))
dense_rank().over(window) 密集排名(不跳号,如 1,2,2,3) df.withColumn("dr", dense_rank().over(windowSpec))
lag(col, n, default).over(window) 取前 n 行值(默认 null) df.withColumn("prev_sal", lag($"salary", 1, 0).over(windowSpec))
lead(col, n, default).over(window) 取后 n 行值(默认 null) df.withColumn("next_sal", lead($"salary", 1, 0).over(windowSpec))
sum(col).over(window) 分区内累计求和 df.withColumn("cum_sum", sum($"salary").over(windowSpec))
ntile(n).over(window) 分区内分桶(均分为 n 组) df.withColumn("ntile", ntile(3).over(windowSpec))

六、其他常用函数

函数 功能说明 示例(Scala DSL)
lit(val) 创建常量列(值转列) df.withColumn("const_col", lit(100))
col("name")/$"name" 引用列($"name" 需 spark.implicits._) df.select(col("name"), $"age")
cast(col, type) 类型转换(StringType/IntegerType 等) df.withColumn("num", $"str_num".cast(IntegerType))
when(cond, val).when(cond2, val2).otherwise(val) 多条件 df.withColumn("level", when($"score">=90,"A").when($"score">=80,"B").otherwise("C"))
greatest(col1, col2, ...) 返回最大值(多列比较) df.withColumn("max_val", greatest($"col1", $"col2", $"col3"))
least(col1, col2, ...) 返回最小值(多列比较) df.withColumn("min_val", least($"col1", $"col2"))
hash(col1, col2, ...) 计算列的哈希值 df.withColumn("hash_val", hash($"name", $"id"))

七、核心使用技巧

  1. 链式调用 :DSL 支持链式操作,简化代码:

    scala 复制代码
    df.select($"name", $"age")
      .filter($"age" > 18)
      .withColumn("age_plus_10", $"age" + 10)
      .groupBy($"name")
      .agg(avg($"age_plus_10").alias("avg_age"))
  2. 列别名 :所有函数结果建议用 alias 命名,避免默认列名(如 abs(num) 列名是 abs(num));

  3. null 处理 :优先用 coalesce/when...otherwise 处理 null 值,避免计算异常;

  4. 隐式转换 :导入 spark.implicits._ 后,支持 $"列名"、数值运算($"a" + $"b")等语法糖。

以上覆盖 SparkSQL DSL(Scala)90%+ 日常开发场景,可根据业务需求组合使用。

相关推荐
yumgpkpm1 天前
Hadoop、Cloudera CDH没有消亡,它是大数据的未来
人工智能·hive·hadoop·spark·kafka·开源·hbase
Lovely Ruby1 天前
前端er Go-Frame 的学习笔记:实现 to-do 功能(四),确保开发和部署共用一套代码
前端·学习·golang
子夜江寒1 天前
使用 Requests 与 Selenium 实现网页数据爬取
python·学习
0和1的舞者1 天前
《Spring Bean&DI 通关笔记:从定义到注入的全场景避坑指南》
java·开发语言·学习·spring·ioc·di·web
青衫码上行1 天前
【JavaWeb学习 | 第20篇】EL表达式与JSTL标签
java·学习·servlet·java-ee
冬夜戏雪1 天前
[java学习]【12.9】【9/60】
学习
玩具猴_wjh1 天前
12.9 学习笔记
笔记·学习
bigdata-rookie1 天前
数据仓库建模
大数据·分布式·spark
专注于大数据技术栈1 天前
java学习--枚举(Enum)
java·学习