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

2024-02-04 08:36

本文主要是介绍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 小结

这篇关于HiveSQL题——collect_set()/collect_list()聚合函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/676904

相关文章

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

Python中合并列表(list)的六种方法小结

《Python中合并列表(list)的六种方法小结》本文主要介绍了Python中合并列表(list)的六种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、直接用 + 合并列表二、用 extend() js方法三、用 zip() 函数交叉合并四、用

PyTorch中cdist和sum函数使用示例详解

《PyTorch中cdist和sum函数使用示例详解》torch.cdist是PyTorch中用于计算**两个张量之间的成对距离(pairwisedistance)**的函数,常用于点云处理、图神经网... 目录基本语法输出示例1. 简单的 2D 欧几里得距离2. 批量形式(3D Tensor)3. 使用不