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 result;
        //负责初始化计算函数并设置它的内部状态,result是存放最终结果的
        @Override
        public void init() {
            result= new HashMap() ;
        }
        //每次对一个新值进行聚集计算都会调用iterate方法
        public boolean iterate(Integer key , Integer value)
        {
            if (result == null )
                result=new  HashMap();
                
            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 terminatePartial()
        {
            return result;
        }
        //合并两个部分聚集值会调用这个方法
        public boolean merge(HashMap other)
        {
            //将 result和other合并
            Iterator> iter = other.entrySet().iterator();
            while (iter.hasNext()) {
                    Map.Entry 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 terminate()
        {
            ArrayList res = new ArrayList() ;
            //先找出最大的value
            int max_value = Integer.MIN_VALUE ;
            Iterator> iter = result.entrySet().iterator();
            while (iter.hasNext()) {
                    Map.Entry entry =  iter.next();
                    int val = entry.getValue();
                    
                    if (val > max_value)
                        max_value = val ;
            }
            
            Iterator> iter2 = result.entrySet().iterator();
            while (iter2.hasNext()) {
                    Map.Entry entry =  iter2.next();
                    int key = entry.getKey();
                    int val = entry.getValue();
                    
                    if (val == max_value)
                        res.add(key) ;
            }
            return res ;
        }
    }
}

你可能感兴趣的:(大数据技术)