Hive学习小记-(6)collect_set与笛卡尔积使用

 场景

有两张表,一张活动清单表actv_evt:记录了所有的活动,包括活动id,活动名称及活动相关配置信息;一张客户活动参与表cust_actv,记录了客户参与活动信息。

cust_actv中参与了活动的客户定义为活跃客户,现在公司想对活跃客户做推广,将没参与过的活动推送给他们

举例:共有actv1, actv2, actv3, actv4,客户cust1参与了actv2, actv4,客户cust2参与了actv1,那么需要找出这样的目标数据:

cust1:actv1,actv3

cust2:actv2,actv3,actv4

原脚本

-- 5.按uid,通过collect_set将每个客户未参加的活动行程组合,如cust1,[actv1, actv3]
select 
     a.cust_uid
    ,concat_ws(',',collect_set(concat_ws(':',actv_id,actv_nm))) as actv
from (
    -- 4.拿步骤3做出来的全客户全活动对应表与b表关联,关联不上的数据就是cust_uid未真实参加的活动,如cust1对应没关联上的记录为cust1,actv1;cust1,actv3
    select
         a.actv_id,a.actv_nm,a.cust_uid
    from (
        -- 3.每个活跃客户与每个活动做笛卡尔积,数据量会很大,目的是做出每个客户与每个活动对应的数据,如对客户1:cust1,actv1;cust1,actv2;cust1,actv3;cust1,actv4
        select
             a.actv_id,a.actv_nm,b.cust_uid
        from (
            -- 2.筛出所有活动清单
            select distinct a.actv_id,a.actv_nm from tb_actv_evt
        ) as a
        left join (
                -- 1.筛选出活跃客户
                select distinct cust_uid from tb_cust_actv
                ) as b
        on 1=1  --笛卡尔积
    ) as a
    left join tb_cust_actv as b
    on a.actv_id=b=actv_id
    and a.cust_uid=b.cust_uid
    where b.actv_id is null
) as a
group by cust_uid

优化一:

可以看出原脚本第1、2步骤两个distinct,3笛卡尔积是消耗资源多的点。本题的笛卡尔积不可避免,但可以减少笛卡尔积的数据量。

-- 3.拿步骤2的所有活动与步骤1参与的活动做差集运算
select 
     b.cust_uid
    ,a.actv_all-b.actv_usd   -- 这里指的是差集运算
from (
-- 1.筛选出活跃客户参与过的活动清单.如客户1:cust1,[actv2, actv4]
    select 
         cust_uid 
        ,collect_set(concat_ws(':',b.actv_id,b.actv_nm) as actv_usd
    from tb_cust_actv as b
    group by cust_uid 
    ) as b
left join (
-- 2.筛出所有活动清单,即[actv1, actv2, actv3, actv4],这时候再笛卡尔积其实相当于b表中每条客户数据只需要与[actv1,actv2,actv3,actv4]这一条数据笛卡尔积
    select 
         collect_set(concat_ws(':',a.actv_id,a.actv_nm) as actv_all
    from tb_actv_evt
    -- group by collect_set(concat_ws(':',a.actv_id,a.actv_nm) collect_set是类似sum,avg的UDAF聚合函数,这里不用group by
    ) as a
on 1=1  --笛卡尔积

 优化二:

优化一的本质是减少笛卡尔积处理的数据量,但是因为笛卡尔积是单条处理的,类似orderby的全局问题,在活跃客户量比较大时,大量客户逐条join一条活动处理仍然很慢,优化程度仍然不够。

 

附:笛卡尔积常用场景

1.常用于给表的每条记录加上一些通用性质(都是单一取值),如本题中整体活动清单(对所有cust活动清单都是一样的,只有单一取值)就是通用的,也可以用于加一些汇总值,通用时间属性等之类。

eg:查看每个项目的营业收入,并且每条数据要附上总营收

select  
     a.proj_name
    ,a.income
    ,b.all_income
    ,b.avg_income
from tb_proj_income
inner join (        -- 在这里添加通用属性。一个优化思路:如果上面的主select语句中有很多通用重复计算,也可以采用将其固定下来在inner join的子查询中
    select 
        sum(income) as all_income
        avg(income) as avg_income  --注意这里sum、avg的取值都是单一的
    from tb_proj_income
    ) as b

--因为除聚合函数,其余字段要加group by, select proj_name,sum(income)实现不了

2.计算留存率等

原文地址:https://www.cnblogs.com/foolangirl/p/14197958.html