日期:2014-05-16  浏览次数:20566 次

Hive.GROUPING SETS的“陷阱”

      之前整理了一下Hive 0.10版引进的GROUPING SETS子句特性,并作了简单的句法使用体验和数据验证。但是当时没有注意到稍微复杂一点的情况,然后,在实际使用过程中,妥妥地就中了一枪。

       这一枪发生在有JOIN操作的时候,情况是这样的:我要对Hive表data_table的a, b, c这3个字段去统计UV和VV这两个数据,并需要由c上卷到b,再上卷到a的统计数据。同时,要对字段b的值进行值映射,这是通过和另外一个专门描述b值的表进行JOIN来实现的。HQL语句如下:

select
         t1.a_desc,
         if(t1.group_bitvector= 1, '未区分', t2.b_desc) as b_desc,
         if(t1.group_bitvector= 1 or t1.group_bitvector = 3, '未区分', t1.c_desc) as c_desc,
         t1.group_bitvector,
         t1.act_uv,
         t1.act_vv
from
(
         select
                   a_desc,
                   b,
                   c_desc,
                   grouping__id as group_bitvector,
                   count(distinctuer_ID) as act_uv,
                   (sum(if(vv_ID is null, 1, 0)) + sum(if(vv_ID = "", 1, 0)) + count(distinct if(vv_ID is not null, if(vv_ID != "", vv_ID, null), null))) as act_vv
         from
         (
                   select
                            (
                                     case a
                                               when 0 then 'str_val_1'
                                               when 1 then 'str_val_2'
                                               when 2 then 'str_val_3'
                                               else 'str_val_4'
                                     end    
                            )as a_desc,
                            b,
                            if(c= -2 or c = -1 or c = 9, 'c_desc1', 'c_desc2') as c_desc,
                            uer_ID,
                            vv_ID
                   from data_table
                   where a = xxx
         ) t
         group by a_desc, b, c_desc
         grouping sets (a_desc,(a_desc, b),(a_desc, b, c_desc))
) t1 join dim_table t2 on (t1.b = t2.b)


       跑出来数据,晃眼一看,是正常的,仔细一看就经不起眼睛的考验了,group_bitvector这一列貌似缺了一个值,这样GROUPING SETS下来,group_bitvector应该出现1, 3, 7这三个值,但是出来的数据竟然没有1,也就是说,缺了最顶层的聚合(只对a进行求聚合)数据!

       用力想了想,才拍脑袋发现了这个微妙的错误,JOIN君扔掉了一些数据!GROUPING SETS不是会把GROUP BY子句中没有参与聚合的列置为NULL么,这些NULL值在JOIN的时候就被无情地抛弃了。。。这个时候,LEFT OUTER JOIN勇敢地站了出来,它说:只要用我替换原来的JOIN(内连接),就可以漂亮地消除了数据被过滤的问题: