You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hive使用collect_set生成用户产品子集时缺失数据的问题排查

问题描述

我在Hive中有如下orders表:

CREATE TABLE orders (
customer_id INT,
date DATE,
product_id INT
);

INSERT INTO orders VALUES
(1, '2024-02-18', 101),
(1, '2024-02-18', 102),
(1, '2024-02-19', 101),
(1, '2024-02-19', 103),
(2, '2024-02-18', 104),
(2, '2024-02-18', 105),
(2, '2024-02-19', 101),
(2, '2024-02-19', 106);

希望得到每个日期下每个用户的所有产品子集,预期结果如下:

date       | partition_set   |
------------|-----------------|
2024-02-18 | [101]           |
2024-02-18 | [101, 102]      |
2024-02-18 | [102]           |
2024-02-18 | [104]           |
2024-02-18 | [104, 105]      |
2024-02-18 | [105]           |
2024-02-19 | [101]           |
2024-02-19 | [101, 103]      |
2024-02-19 | [103]           |
2024-02-19 | [106]           |
2024-02-19 | [101, 106]      |

我尝试了以下查询:

select `date`, customer_id , COLLECT_SET(TRIM(upper(product_id)))  
over(PARTITION by  `date`, customer_id ORDER by customer_id,upper(product_id)) prd
from reporting.tmp_orders;

得到的结果中,用户1在2024-02-18的结果缺少了[102]这一行,请问我的查询哪里出错了?需要用Hive实现该需求,而非Python。

错误原因分析

你当前的查询用了窗口函数COLLECT_SET()加ORDER BY,这种写法会生成累积的集合,而不是所有可能的子集。以用户1在2024-02-18的数据为例:

  • 第一条记录(product_id=101)生成[101]
  • 第二条记录(product_id=102)生成[101,102]
    但窗口函数只会为每一行生成对应位置的累积集合,不会单独生成只包含102的集合,所以自然缺少[102]这一行。

另外,TRIM(upper(product_id))是多余的——product_id是INT类型,转大写、修剪字符串操作毫无意义,反而可能引发类型转换问题。

正确Hive实现方案

要生成每个用户每日所有产品的非空子集,这里提供两种可行的实现方式:

方式一:自关联生成子集(适合产品数量较多的场景)

WITH user_daily_products AS (
    -- 为每个用户每日的产品分配序号
    SELECT 
        `date`,
        customer_id,
        product_id,
        ROW_NUMBER() OVER(PARTITION BY `date`, customer_id ORDER BY product_id) AS rn
    FROM orders
),
product_combinations AS (
    -- 自关联生成连续的产品组合
    SELECT 
        a.`date`,
        COLLECT_LIST(b.product_id) AS partition_set
    FROM user_daily_products a
    JOIN user_daily_products b 
        ON a.`date` = b.`date` 
        AND a.customer_id = b.customer_id 
        AND b.rn >= a.rn
    GROUP BY a.`date`, a.customer_id, a.rn
)
-- 去重并排序输出
SELECT DISTINCT
    `date`,
    partition_set
FROM product_combinations
ORDER BY `date`, partition_set;

方式二:位运算生成子集(适合产品数量较少的场景)

WITH user_daily_product_lists AS (
    -- 先聚合每个用户每日的产品列表
    SELECT 
        `date`,
        customer_id,
        COLLECT_LIST(product_id) AS product_list
    FROM orders
    GROUP BY `date`, customer_id
),
subset_generation AS (
    -- 利用位运算生成所有非空子集
    SELECT 
        `date`,
        COLLECT_LIST(product_list[pos]) AS partition_set
    FROM user_daily_product_lists
    LATERAL VIEW posexplode(product_list) pe AS pos, product
    LATERAL VIEW generate_series(1, pow(2, SIZE(product_list)) - 1) gs AS num
    WHERE BITGET(num, pos) = 1
    GROUP BY `date`, customer_id, num
)
-- 输出结果
SELECT 
    `date`,
    partition_set
FROM subset_generation
ORDER BY `date`, partition_set;

内容的提问来源于stack exchange,提问作者Param

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:42:41