Spark SQL自定义collect_list分组排序

想要在spark sql中对group by + concat_ws()的字段进行排序,可以参考如下方法。

原始数据如下:

java 复制代码
+---+-----+----+
|id |name |type|
+---+-----+----+
|1  |name1|p   |
|2  |name2|p   |
|3  |name3|p   |
|1  |x1   |q   |
|2  |x2   |q   |
|3  |x3   |q   |
+---+-----+----+

目标数据如下:

java 复制代码
+----+---------------------+
|type|value_list           |
+----+---------------------+
|p   |[name3, name2, name1]|
|q   |[x3, x2, x1]         |
+----+---------------------+

spark-shell:

java 复制代码
val df=Seq((1,"name1","p"),(2,"name2","p"),(3,"name3","p"),(1,"x1","q"),(2,"x2","q"),(3,"x3","q")).toDF("id","name","type")
df.show(false)

1.使用开窗函数

java 复制代码
df.createOrReplaceTempView("test")
spark.sql("select type,max(c) as c1 from (select type,concat_ws('&',collect_list(trim(name)) over(partition by type order by id desc)) as c  from test) as x group by type ")

因为使用开窗函数本身会使用比较多的资源,

这种方式在大数据量下性能会比较慢,所以尝试下面的操作。

2.使用struct和sort_array(array,asc?true,flase)的方式来进行,效率高些:

java 复制代码
val df3=spark.sql("select type, concat_ws('&',sort_array(collect_list(struct(id,name)),false).name) as c from test group by type ")
df3.show(false)

例如:计算一个结果形如:

java 复制代码
user_id    stk_id:action_type:amount:price:time   stk_id:action_type:amount:price:time   stk_id:action_type:amount:price:time   stk_id:action_type:amount:price:time 

需要按照time 升序排,则:

java 复制代码
Dataset<Row> splitStkView = session.sql("select client_id, innercode, entrust_bs, business_amount, business_price, trade_date from\n" +
                "(select client_id,\n" +
                "       split(action,':')[0] as innercode,\n" +
                "       split(action,':')[1] as entrust_bs,\n" +
                "       split(action,':')[2] as business_amount,\n" +
                "       split(action,':')[3] as business_price,\n" +
                "       split(action,':')[4] as trade_date,\n" +
                "       ROW_NUMBER() OVER(PARTITION BY split(action,':')[0] ORDER BY split(action,':')[4] DESC) AS rn\n" +
                "from stk_temp)\n" +
                "where rn <= 5000");
        splitStkView.createOrReplaceTempView("splitStkView");
        Dataset<Row> groupStkView = session.sql("select client_id, CONCAT(innercode, ':', entrust_bs, ':', business_amount, ':', business_price, ':', trade_date) as behive, trade_date from splitStkView");
        groupStkView.createOrReplaceTempView("groupStkView");
        Dataset<Row> resultData = session.sql("SELECT client_id, concat_ws('\t',sort_array(collect_list(struct(trade_date, behive)),true).behive) as behives FROM groupStkView GROUP BY client_id");
        

3.udf的方式

java 复制代码
import org.apache.spark.sql.functions._
import org.apache.spark.sql._
val sortUdf = udf((rows: Seq[Row]) => {
  rows.map { case Row(id:Int, value:String) => (id, value) }
    .sortBy { case (id, value) => -id } //id if asc
    .map { case (id, value) => value }
})

val grouped = df.groupBy(col("type")).agg(collect_list(struct("id", "name")) as "id_name")
val r1 = grouped.select(col("type"), sortUdf(col("id_name")).alias("value_list"))
r1.show(false)
相关推荐
starzy199012 小时前
SparkStreaming 之 Direct 模式深度剖析
大数据·spark
山峰哥13 小时前
数据库工程与查询优化案例深度复盘‌
数据库·sql·oracle·编辑器·深度优先·宽度优先
JLWcai2025100915 小时前
树脂砂轮质保与科学存放
mongodb·zookeeper·spark·memcached·storm
茶栀(*´I`*)16 小时前
数据库零基础入门指南:从基本概念到 SQL 实战
数据库·sql
zcn12617 小时前
exists子查询改写思考
数据库·sql·sql优化改写
黄俊懿17 小时前
【架构师从入门到进阶】第五章:DNS&CDN&网关优化思路——第八节:网关-注入攻击与预防
sql·网络安全·架构·系统架构·架构师·架构设计
用户36105886261219 小时前
SparkStreaming 之 DStream 底层结构剖析
大数据·spark
贾伟康20 小时前
【天体运行模拟|03】HarmonyOS ArkTS 场景选择实战:组织行星、卫星与天文现象入口
list·harmonyos·arkts·arkui·页面路由
HackTwoHub21 小时前
Butter_Cookie 黄油曲奇|浏览器渗透插件,云存储检测、XSS、SQL 注入一站式 Web 安全测试工具
前端·sql·安全·web安全·网络安全·自动化·xss
Sagittarius_A*21 小时前
【好靶场】报错注入-sql注入-数字型
数据库·sql·web安全·sql注入