一文说清楚Hive中常用的聚合函数[collect_list]

一文说清楚Hive中常用的聚合函数[collect_list]

collect_list(col)是Hive中常用的聚合函数,用于将分组内的某列值(col)收集到一个数组中。它的核心作用是将多行数据合并为单行的数组结构,常用于数据重组或复杂分析场景。以下是详细说明和示例:

一、函数特点

  1. 分组聚合:需配合GROUP BY使用,将每个分组内的col值收集为数组。
  2. 保留重复值:与collect_set(col)不同,collect_list不会去重,保留所有原始值(包括重复值)。
  3. 顺序不确定:默认不保证数组内元素的顺序(除非配合窗口函数ORDER BY)。

二、典型应用场景

  1. 用户行为序列分析:将用户的多次操作按时间串联为行为路径。
  2. 数据结构转换:将行式存储的数据转为列式(如将多行商品标签转为单个商品的标签数组)。
  3. 复杂统计:计算每个分组内的所有值的列表(如收集每个班级的所有学生成绩)。

三、示例演示

场景1:用户订单列表收集

需求:收集每个用户的所有订单ID,生成用户ID → [订单ID列表]的映射。
数据

user_id | order_id ------------------ 1 | 1001 1 | 1002 2 | 1003 2 | 1003 -- 重复订单 3 | 1004 

HQL

SELECT user_id, collect_list(order_id)AS order_list -- 收集订单ID到数组FROM orders GROUPBY user_id;

结果

user_id | order_list --------------------- 1 | [1001, 1002] 2 | [1003, 1003] -- 保留重复值 3 | [1004] 
场景2:按时间排序的用户行为路径

需求:将用户的点击行为按时间顺序串联为路径(如首页→商品页→购物车)。
数据user_behavior表):

user_id | action_time | page ----------------------------------- 1 | 2025-07-24 10:00:00 | 首页 1 | 2025-07-24 10:05:00 | 商品页 1 | 2025-07-24 10:10:00 | 购物车 2 | 2025-07-24 09:30:00 | 搜索页 2 | 2025-07-24 09:40:00 | 商品页 

HQL

SELECT user_id, concat_ws('→', collect_list(page ORDERBY action_time))AS behavior_path FROM user_behavior GROUPBY user_id;

结果

user_id | behavior_path ------------------------ 1 | 首页→商品页→购物车 2 | 搜索页→商品页 

关键点

  • ORDER BY action_time确保数组元素按时间排序。
  • concat_ws('→', ...)将数组元素用连接为字符串。
场景3:JSON数组生成(结合explode反向操作)

需求:将每个商品的多个标签从多行转为JSON数组格式。
数据product_tags表):

product_id | tag ----------------- 101 | 电子产品 101 | 手机 102 | 服装 102 | 男装 102 | 休闲装 

HQL

SELECT product_id, collect_list(tag)AS tags_array -- 生成标签数组FROM product_tags GROUPBY product_id;

结果

product_id | tags_array ------------------------- 101 | ["电子产品", "手机"] 102 | ["服装", "男装", "休闲装"] 

延伸:若需转为JSON字符串,可结合to_json()函数:

to_json(collect_list(tag))AS tags_json -- 输出:"["电子产品","手机"]"

四、注意事项

  1. 内存风险:若单个分组的数据量过大(如某个用户有百万级订单),可能导致OOM(内存溢出),需控制分组数据规模或增加内存。
  2. collect_set对比
    • collect_list保留重复值,且不保证顺序(除非显式ORDER BY)。
    • collect_set自动去重,但同样不保证顺序。
  3. 数组长度限制:默认无限制,但过长的数组会影响性能,建议结合业务逻辑提前过滤无效数据。

五、性能优化建议

配合窗口函数排序:若需严格按时间排序,可先通过窗口函数生成排序字段,再collect_list

WITH sorted_orders AS(SELECT user_id, order_id, ROW_NUMBER()OVER(PARTITIONBY user_id ORDERBY order_time)AS rn FROM orders )SELECT user_id, collect_list(order_id ORDERBY rn)AS ordered_orders FROM sorted_orders GROUPBY user_id;

过滤先行:在GROUP BY前通过WHERE减少数据量,避免不必要的计算。
示例:

SELECT user_id, collect_list(order_id)FROM orders WHERE order_date >='2025-01-01'-- 先过滤近一年订单GROUPBY user_id;

通过collect_list,可高效地将多行数据合并为结构化数组,为复杂分析(如路径挖掘、序列预测)提供基础,是Hive中处理“一对多”关系的核心工具之一。

Read more

手撕力扣138题:优雅复制带随机指针的链表,三步搞定经典算法题

手撕力扣138题:优雅复制带随机指针的链表,三步搞定经典算法题

手撕力扣138题✨:优雅复制带随机指针的链表,三步搞定经典算法题 * 一、题目核心剖析🔍 * 题目要求 * 解题难点 * 节点结构定义(C++) * 二、核心解题思路💡:三步法原地复制 * 步骤1:原地插入复制节点,打造“原节点-复制节点”成对链表 * 图形演示 * 核心代码片段 * 步骤2:修正复制节点的random指针,指向正确的复制节点 * 图形演示 * 核心代码片段 * 步骤3:拆分原链表与复制链表,得到最终的深拷贝链表 * 图形演示 * 核心代码片段 * 三、完整C++代码实现📝 * 四、算法性能分析📊 * 时间复杂度 * 空间复杂度 * 对比哈希表法 * 五、解题总结与拓展📚 * 解题核心要点 * 算法拓展 在链表的算法考察中,带随机指针的链表复制绝对是高频考点,力扣138题虽被标注为中等难度,但实则是锻炼链表操作思维的经典简单题。普通链表的复制仅需遍历处理next指针即可,而带random随机指针的链表,因random可

By Ne0inhk
【算法通关指南:数据结构与算法篇】二叉树相关算法题:1.美国血统 American Heritage 2.二叉树问题

【算法通关指南:数据结构与算法篇】二叉树相关算法题:1.美国血统 American Heritage 2.二叉树问题

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、美国血统 American Heritage * 1.1题目 * 1.2 算法原理 * 1.3代码 * 二、 二叉树问题 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 总结与每日励志 前言 本专栏聚焦算法题实战,系统讲解算法模块:以《c++编程》,《数据结构和算法》《基础算法》《算法实战》 等几个板块以题带点,讲解思路与代码实现,帮助大家快速提升代码能力ps:本章节题目分两部分,比较基础笔者只附上代码供大家参考,其他的笔者会附上自己的思考和讲解,希望和大家一起努力见证自己的算法成长 一、

By Ne0inhk
算法王冠上的明珠——动态规划之斐波那契数列问题(第二篇)

算法王冠上的明珠——动态规划之斐波那契数列问题(第二篇)

目录 1. LeetCode746. 使用最小花费爬楼梯 2. LeetCode91. 解码方法 今天我们继续来聊一聊动态规划的斐波那契数列类型的题目 1. LeetCode746. 使用最小花费爬楼梯 这个题目的话也是比较简单的。就是要求我们计算在可以一次走一步或者两步的情况下,到达结尾时的最小消耗。 所以在这道题里面它的状态表示就是走到当前位置的值的最小消耗。 所以在这道题里面它的状态转移方程就是dp[i]=min(dp[i-1],dp[i-2])+c[i]。 它的初始化就是第0个位子设置为c[0],第一个位置设置为c[1]。(怎么设置是因为我们是不知道开始的那个位置的大小,而且因为我们的状态转移方程需要依靠前两个位置的值,所以我们在这里就直接初始化前两个)。 填表顺序就是从前往后就好。 返回值就是dp表第sz-1个位置的值和第sz-2个位置的值的最小值。 class Solution { public: int minCostClimbingStairs(vector<int>& c) { int sz=c.size(); vector<

By Ne0inhk
【数据结构-初阶】详解线性表(5)---队列

【数据结构-初阶】详解线性表(5)---队列

🎈主页传送门:良木生香 🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》 🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离 上期回顾:在上一篇文章(【数据结构-初阶】详解栈和队列(1)---栈)中我们讲到了在顺序表与链表之外的另一种线性表---栈,知道了这是一种具有先进后出和后进先出特点的数据结构,既然有先进后出,那么肯定就有先进先出的数据结构,所以这就是我们今天要讲的------队列 一、队列的概念 既然我们想要实现先进先出的效果,那肯定就不像栈那样有一端是堵起来的,想必应该是两端都开口吧。嗯,事实确实如此。 队列:是只允许在一端进行数据的插入操作,在另一端进行数据的删除操作的一种特殊的线性表,其具有先进先出FIFO(first in first out)的结构特点. 入队列:进行插入操作的一端叫做队尾 出队列:进行删除操作的一端叫做队头 下面是队列的示意图: 名字叫做队列,其实就像我们排队一样,先排的人先得服务,后排的人后得到服务,在队列中,先进来的元素先得到操作,

By Ne0inhk