HiveSQL题——collect_set()/collect_list()聚合函数

一、collect_set() /collect_list()介绍

       collect_set()函数与collect_list()函数属于高级聚合函数(行转列),将分组中的某列转换成一个数组返回,常与concat_ws()函数连用实现字段拼接效果。

  • collect_list:收集并形成list集合,结果不去重

  • collect_set:收集并形成set集合,结果去重

二、collect_set() /collect_list()有序性

0 问题描述

  有一张用户关注表table20,需求:根据用户user_id分组,按照粉丝关注的时间升序排序,输出粉丝id数组粉丝关注的时间数组,并保障两个数组的数据能一一对应

1 数据准备

create table if not exists table20 (user_id int comment '用户id',follow_user_id int comment '粉丝id',update_time string comment '粉丝关注的时间'
) comment  '用户关注表';insert overwrite table table20 values
(1, 101,'2021-09-30 10:12:00'),
(1, 103,'2021-10-01 11:00:00'),
(1, 104,'2021-11-02 10:00:00'),
(1, 103,'2021-11-28 10:22:00'),
(2, 104,'2021-11-02 10:11:00'),
(2, 100,'2021-11-03 10:21:00'),
(1, 99,'2021-11-23 12:28:00');

2 数据分析

方式一: row_number() over(partition by .. order by..) as rn 排序,然后再使用collect_list()/collect_set()进行聚合.

selectuser_id,concat_ws('|', collect_list(cast(follow_user_id as string))) as fui,concat_ws('|', collect_list(update_time))  as utfrom (selectuser_id,follow_user_id,update_time,row_number() over (partition by user_id order by update_time) rnfrom table20) tmp1
group by user_id;

发现问题:ut数组内的时间并没有按照升序排序输出。

原因分析:

  • HiveSQL执行时,底层转换成MR任务执行,当同时开启多个mapper任务时,mapper1可能处理的user_id是 1,update_time排名为1,2,3的数据,mapper2可能处理的user_id是1,update_time排名为4,5的数据。
  • collect_list()的底层是arrayList 来实现的,当put到arrayList集合时,无法知道是哪个mapper先计算完,所以可能会出现ArrayList集合中的数据顺序与原来数据插入的顺序不对齐的情况。因此:row_number() over(partition by .. order by ..) 与collect_list一起使用的时候,只能是实现局部有序(单个mapper的数据有序),不能实现全局有序。

解决方案:

方案一:使用distribute by + order by

selectuser_id,concat_ws('|', collect_list(cast(follow_user_id as string))) as fui_list,concat_ws('|', collect_list(update_time))                    as ut_list
from (selectuser_id,follow_user_id,update_time,row_number() over (partition by user_id order by update_time ) as rnfrom (selectuser_id,follow_user_id,update_timefrom table20distribute by user_id sort by update_time) tmp1) tmp2
group by user_id
order by user_id;

 上述代码用到的函数:

(1)concat_ws:带分隔符的字符串连接语法: concat_ws(string SEP, string A, string B…)select concat_ws('-','abc','def') // abc-def(2)collect_list:收集并形成list集合,结果不去重语法:select id, collect_list(likes) from student group by id;(2)collect_set:收集并形成set集合,结果去重语法:select id, collect_set(likes) from student group by id;

方案二:sort_array(只支持升序)

selectuser_id,concat_ws(',', collect_list(cast(follow_user_id as string)))   as fui,concat_ws(',', sort_array(collect_list(concat_ws('|', lpad(cast(rn as string), 2, '0'), update_time)))) as middle,regexp_replace(concat_ws(',', sort_array(collect_list(concat_ws('|', lpad(cast(rn as string), 2, '0'), update_time)))), '\\d+\\|', '') as ut
from (selectuser_id,follow_user_id,update_time,rnfrom (selectuser_id,follow_user_id,update_time,row_number() over (partition by user_id order by update_time ) as rnfrom table20) tmp1order by rn) tmp2
group by user_id
order by user_id

middle字段值的结果:

ut字段值的结果:

select regexp_replace('04|','\\d+\\|','*')  --> *
正则表达式:\\d+代表所有数字字符

上述代码用到的函数:

(一)lpad / rpad:左/右补足函数
语法:lpad(string str, int len,string pad) / rpad(string str, int len, string pad)
参数说明:
第一个参数:要补齐的字符串
第二个参数:补齐之后字符串的总位数
第三个参数:从左边/右边填充的字符, lpad代表从左边填充;rpad代表从右边填充举例:
select lpad('abc',5,'fg')  --> fgabc
select rpad('abc',7,'df') --> abcdfdf因为sort_array 是按照顺序对字符进行排序(例如11会排在2前面),所以可以使用函数lpad补位(将原来的1,2,3,4 转换成 01,02,03,04),然后再正常排序(二)regexp_replace : 字符串替换
语法:regexp_replace(string initial_string, string pattern, string  replacement)
参数说明:initial_string为要替换的字符串,pattern为匹配字符串的正则表达式,replacement为要替换为的字符串。
简述: regexp_replace (StrA,StrB,StrC) 函数:将字符串A中的符合java正则表达式B的部分替换成C(三)sort_array : 数组排序函数语法:sort_array(array, [asc|desc]) : 按照指定的排序规则对数组进行排序,并返回一个排好序的新数组参数说明:第一个参数:array为需要排序的数组,第二个参数:asc为可选参数,如果设置为true则按升序排序;desc为可选参数,如果设置为true,则按降序排序。如果既不设置asc也不设置desc,则按升序排序举例:
select sort_array(array(2, 5, 3, 1)) as sorted_array; ---> [1,2,3,5]
select sort_array(array(2, 5, 3, 1), true, true) as sorted_array; ---> [5,3,2,1]

3 小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/451414.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPT3.5\GPT4系列计算完整prompt token数的官方方法

前言: ChatGPT如何计算token数?https://wtl4it.blog.csdn.net/article/details/135116493?spm1001.2014.3001.5502https://wtl4it.blog.csdn.net/article/details/135116493?spm1001.2014.3001.5502 GPT3.5\GPT4系列计算完整prompt token数的官方方法&#xff1…

集成阿里云短信服务

目的是集成阿里云短信服务,完成验证码的发送和接收。 目 录 1、开通阿里云短信服务 2、申请签名 3、申请模板 4、获取AccessKey 5、代码实现 6、代码扩展 7、总结 1、开通阿里云短信服务 去阿里云官网开通 2、申请签名 进行整个步骤时,可以先…

XUbuntu22.04之如何创建、切换多个工作区(二百零九)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

项目02《游戏-05-开发》Unity3D

基于 项目02《游戏-04-开发》Unity3D , 【任务】UI背包系统, 首先将Game窗口设置成1920 * 1080, 设置Canvas的缩放模式,:这样设置能让窗口在任意分辨率下都以一个正确的方式显示, 设置数值&…

Grafana实现在同一个面板中多个query应用不同的Data source

目的:实现在同一个面板中多个query应用不同的Data source如下图: 目前A、B都应用的是prometheus源,实现A、B两个query可以应用不同的Data source源 1.添加多个源: 2.点击需要应用多个源的面板,选择上面的设置按钮。 …

2024美赛C题完整解题教程及代码 网球运动的势头

2024 MCM Problem C: Momentum in Tennis (网球运动的势头) 注:在网球运动中,"势头"通常指的是比赛中因一系列事件(如连续得分)而形成的动力或趋势,这可能对比赛结果产生重要影响。球…

【Android】RxJava系列01-基本概述和基本用法

少年啊,要永远相信美好的事情即将发生 【Android】RxJava系列01-基本概述和基本用法 1.RxJava的概述2.RxJava的作用3.观察者和被观察者4.背压5.RxJava的基本用法步骤一,创建Observer(观察者)步骤二,创建Observable&…

【C++】类和对象之运算符重载(三)

前言:在前面我们知道在类和对象中有六个默认成员函数,并学习了其中三个构造函数、析构函数、拷贝构造函数,今天我们将进一步的学习.赋值运算符重载。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:高质…

【API接口】制造企业,电商API接口面临的一道难题——数据采集

数据采集一直是困扰着所有制造工厂的传统痛点,自动化设备品牌类型繁多,厂家和数据接口各异,国外厂家本地支持有限,不同采购年代。即便产量停机数据自动采集了,也不等于整个制造过程数据都获得了,只要还有其…

计算机网络_1.6.2 计算机网络体系结构分层的必要性

1.6.2 计算机网络体系结构分层的必要性 一、五层原理体系结构每层各自主要解决什么问题1、物理层2、数据链路层3、网络层4、运输层5、应用层 二、总结三、练习 笔记来源: B站 《深入浅出计算机网络》课程 本节主要介绍实现计算机网络需要解决哪些问题?以…

【XR806开发板试用】TCP通信测试 Ping 命令测试

1.工程准备 由于要使用wifi功能,直接从wlan_demo复制一份出来,然后修改。 源文件只留下 main.c 就可以了。 BUILD.gn文件 import("//device/xradio/xr806/liteos_m/config.gni")static_library("app_mying") {configs []sources…

LeetCode 热题 100 | 链表(中下)

目录 1 19. 删除链表的倒数第 N 个节点 2 24. 两两交换链表中的节点 3 25. K 个一组翻转链表 4 138. 随机链表的复制 菜鸟做题第三周,语言是 C 1 19. 删除链表的倒数第 N 个节点 到底是节点还是结点。。。 解题思路: 设置双指针 left 和 ri…