hive优化:让一个MR做更多的事情

常常会有类似这样的需求:
数据是这样的
user_id  int      用户ID        
pay_channel int   充值渠道ID
pay_cents   int   充值金额
user_id+pay_channel为唯一键
求每个用户充值金额最多的渠道。


直观上有两种思路:
1. 先求每个用户在所有渠道上的最大充值,然后回表join
select t1.user_id , t1.pay_channel 
from table t1 join
(
    select user_id , max(pay_cents) max_pay from table group by user_id
) t2 on (t1.user_id = t2.user_id and t1.pay_cents = t2.max_pay)  ;


2.用先分析函数对pay_cent做排名标记,再用排名来过滤
select user_id , pay_channel from 
(
    select 
        user_id , pay_channel , rank(pay_cents)over)(partition by user_id ) rk
    from table 
) t1 
where rk = 1 ;




上面两个方法都需要两个MR来完成。
根据Hive的特性,我们可以有第三种思路,通过UDAF用一个MR完成。
select user_id , getKeyWithMaxValue(pay_channel , pay_cents) max_channels 
from table 
group by user_id ;


getKeyWithMaxValue(key , value)是我自定义的UDAF,用来求最大value所对应的key,这样的key可能是多个,所以返回值是list.


UDAF实现代码如下:

public class GetKeyWithMaxValue extends UDAF {
  
    public static class GetKeyWithMaxValue_int_int implements UDAFEvaluator{
        //最终结果
        private HashMap<Integer , Integer > result;
        //负责初始化计算函数并设置它的内部状态,result是存放最终结果的
        @Override
        public void init() {
            result= new HashMap<Integer , Integer >() ;
        }
        //每次对一个新值进行聚集计算都会调用iterate方法
        public boolean iterate(Integer key , Integer value)
        {
            if (result == null )
                result=new  HashMap<Integer , Integer >();
                
            if(result.containsKey(key))
            {
                int new_value = result.get(key) ;
                if (new_value < value)
                    new_value = value ;
                result.put(key , new_value) ;
            }
            else 
                result.put( key , value ) ;
            
            return true;
        }
                                                                                                                                 
        //Hive需要部分聚集结果的时候会调用该方法
        //会返回一个封装了聚集计算当前状态的对象
        public HashMap<Integer , Integer > terminatePartial()
        {
            return result;
        }
        //合并两个部分聚集值会调用这个方法
        public boolean merge(HashMap<Integer , Integer > other)
        {
            //将 result和other合并
            Iterator<Entry<Integer, Integer>> iter = other.entrySet().iterator();
            while (iter.hasNext()) {
                    Map.Entry<Integer , Integer> entry =  iter.next();
                    int key = entry.getKey();
                    int val = entry.getValue();
            
                if(result.containsKey(key))
                {
                    int new_value = result.get(key) ;
                    if (new_value < val)
                        new_value = val ;
                    result.put(key , new_value) ;
                }
                else 
                    result.put( key , val ) ;
            }
            return true ;
        }
        //Hive需要最终聚集结果时候会调用该方法
        public ArrayList<Integer> terminate()
        {
            ArrayList<Integer> res = new ArrayList<Integer>() ;
            //先找出最大的value
            int max_value = Integer.MIN_VALUE ;
            Iterator<Entry<Integer, Integer>> iter = result.entrySet().iterator();
            while (iter.hasNext()) {
                    Map.Entry<Integer , Integer> entry =  iter.next();
                    int val = entry.getValue();
                    
                    if (val > max_value)
                        max_value = val ;
            }
            
            Iterator<Entry<Integer, Integer>> iter2 = result.entrySet().iterator();
            while (iter2.hasNext()) {
                    Map.Entry<Integer , Integer> entry =  iter2.next();
                    int key = entry.getKey();
                    int val = entry.getValue();
                    
                    if (val == max_value)
                        res.add(key) ;
            }
            return res ;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值