【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%+ 日常开发场景,可根据业务需求组合使用。

相关推荐
肌肉娃子2 天前
20260227.spark.Spark 性能刺客:千万别在 for 循环里写 withColumn
spark
西岸行者3 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
B站计算机毕业设计超人3 天前
计算机毕业设计Django+Vue.js音乐推荐系统 音乐可视化 大数据毕业设计 (源码+文档+PPT+讲解)
大数据·vue.js·hadoop·python·spark·django·课程设计
十月南城3 天前
数据湖技术对比——Iceberg、Hudi、Delta的表格格式与维护策略
大数据·数据库·数据仓库·hive·hadoop·spark
悠哉悠哉愿意3 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码3 天前
嵌入式学习路线
学习
毛小茛3 天前
计算机系统概论——校验码
学习
babe小鑫3 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms3 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs