HIVE UDAF 定制 AVG

需求:在hive里我们要一个自定义的 求平均值 方法 ,因为 普通的 avg 会受极大值印象 

     (做统计的同学你们懂的!)

CREATE TEMPORARY FUNCTION c_avg  AS 'ccindex.hive.udaf.Avg';

源码 :

点击(此处)折叠或打开

  1. package ccindex.hive.udaf;

  2. /**
  3.  * 参考 :
  4.  *   UDAF : http://www.fuzhijie.me/?p=118
  5.  *   对象序列化参考 : http://oss-dataturbine.googlecode.com/svn/trunk/dev/j2me-rbnb/src/com/rbnb/utility/ByteConvert.java
  6.  */
  7. import java.io.DataInput;
  8. import java.io.DataOutput;
  9. import java.io.IOException;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import java.util.Set;

  13. import org.apache.hadoop.hive.ql.exec.UDAF;
  14. import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
  15. import org.apache.hadoop.io.BinaryComparable;
  16. import org.apache.hadoop.io.WritableComparable;

  17. import ccindex.util.ByteUtils;
  18. import ccindex.util.NumUtils;

  19. public class Avg extends UDAF {
  20.     
  21.     public static class avgScore extends BinaryComparable implements
  22.             WritableComparable<BinaryComparable> {
  23.         
  24.         private Map< Float, Integer> datas = new HashMap<Float, Integer>() ;
  25.         
  26.         public void clear(){
  27.             datas.clear();
  28.         }
  29.         
  30.         public void set(Float f,Integer c){
  31.             if( datas.containsKey(f) ){
  32.                 datas.put(f, datas.get(f)+c);
  33.             }else{
  34.                 datas.put(f,c);
  35.             }
  36.         }
  37.         
  38.         public Set<Map.Entry<Float, Integer>> getAll(){
  39.             return datas.entrySet();
  40.         }
  41.         
  42.         public Integer get(Float f){
  43.             return datas.get(f);
  44.         }
  45.         
  46.         @Override
  47.         public void readFields(DataInput in) throws IOException {
  48.             datas.clear();
  49.             
  50.             int size = in.readInt();
  51.             System.out.println(size);
  52.             float[] fs = new float[size];
  53.             int[] is = new int[size];
  54.             
  55.             for (int i = 0; i < size; i++) {
  56.                 fs[i] = in.readFloat();
  57.             }
  58.             
  59.             for (int i = 0; i < size; i++) {
  60.                 is[i]=in.readInt();
  61.             }
  62.             
  63.             for (int i = 0; i < size; i++) {
  64.                 datas.put(fs[i], is[i]);
  65.             }
  66.         }

  67.         @Override
  68.         public void write(DataOutput out) throws IOException {
  69.             byte[] bytes = getBytes();
  70.             out.write(bytes);
  71.         }

  72.         @Override
  73.         public byte[] getBytes() {
  74.             // 获取 收集 总条数
  75.             int size = datas.size();
  76.             
  77.             /* 序列化 byte 格式 :
  78.              * 1. 总条数 = int
  79.              * 2. 速度 float [list] ,精确到 小数点后两位
  80.              * 3. 速度 float ,在此次收集中 出现的次数 [list]
  81.              */
  82.             byte[] bi = ByteUtils.int2Byte(new int[]{size});
  83.             
  84.             byte[] ret_byte = new byte[getLength()];
  85.             // 拷贝 总条数 到 ret_byte 的最前面 
  86.             ByteUtils.byteInbyte(ret_byte, 0, bi, 0, bi.length);
  87.             
  88.             float[] fs = new float[size] ;
  89.             int[] is = new int[size] ;
  90.             
  91.             int step = 0 ;
  92.             for (Map.Entry<Float, Integer> kv : datas.entrySet()) {
  93.                 fs[step] = kv.getKey();
  94.                 is[step] = kv.getValue();
  95.                 step ++ ;
  96.             }
  97.             byte[] bfs = ByteUtils.float2Byte(fs); 
  98.             byte[] bis = ByteUtils.int2Byte(is); 
  99.             
  100.             ByteUtils.byteInbyte(ret_byte, bi.length,bfs , 0, bfs.length);
  101.             ByteUtils.byteInbyte(ret_byte, bi.length +bfs.length ,bis , 0, bis.length);
  102.             
  103.             return ret_byte ;
  104.         }

  105.         @Override
  106.         public int getLength() {
  107.             // 获取 收集 总条数
  108.             int size = datas.size();
  109.             return (Integer.SIZE + size*Float.SIZE + size*Integer.SIZE)/Byte.SIZE;
  110.         }

  111.     }

  112.     public static class AvgEvaluator implements UDAFEvaluator {
  113.         avgScore score;

  114.         public AvgEvaluator() {
  115.             score = new avgScore();
  116.             init();
  117.         }

  118.         /*
  119.          * init函数类似于构造函数,用于UDAF的初始化
  120.          */
  121.         public void init() {}
  122.         
  123.         /*
  124.          * iterate接收传入的参数,并进行内部的轮转。其返回类型为boolean类似Combiner中的mapper
  125.          */
  126.         public boolean iterate(Float ff) {
  127.             if(ff!=null){
  128.                 // 为节省 空间 ,float 精确到小声点后两位 
  129.                 float f1 = NumUtils.floatDecimalPlaces(new float[]{ff},2)[0];
  130.                 score.set(f1, 1);    
  131.             }
  132.             return true;
  133.         }

  134.         /*
  135.          * terminatePartial无参数,其为iterate函数轮转结束后
  136.          *     返回轮转数据类似Combiner中的reducer
  137.          */
  138.         public avgScore terminatePartial() {
  139.             return score.getLength() == 0 ? null : score;
  140.         }

  141.         /*
  142.          * merge接收terminatePartial的返回结果,进行数据merge操作
  143.          *     其返回类型为boolean
  144.          */
  145.         public boolean merge(avgScore in) {
  146.             for (Map.Entry<Float, Integer> kv : in.getAll()) {
  147.                 score.set(kv.getKey(), kv.getValue());
  148.             }
  149.             return true;
  150.         }

  151.         /*
  152.          * terminate返回最终的聚集函数结果
  153.          */
  154.         public float terminate() {
  155.             float all = 0f ;
  156.             
  157.             int num = 0 ;
  158.             for (Map.Entry<Float, Integer> kv : score.getAll()) {
  159.                 all += kv.getKey() * kv.getValue();
  160.                 num += kv.getValue();
  161.             }
  162.             
  163.             /*注意:
  164.              *     发现分配到某台reduce上的 多个 group key 会顺序使用这个 对象 的
  165.              *     在每个 group key 后都需要清除内存 */
  166.             score.clear();
  167.             
  168.             return all/num;
  169.         }
  170.     }
  171.     
  172. }

你可能感兴趣的:(HIVE UDAF 定制 AVG)