回头看了看之前自定义的UDF,UDAF,UDTF,竟然有种生疏的感觉,因此,对于其中的代码重新做了注释,更加的详细和容易理解,下面就是我自己定义的几个样例,比较简单,主要是通过样例来了解如何自定义UDF来完成需求。

1、UDAF

需求是找出指定字段的topN,数据类型定义为double,下面是实现代码。



package com.wangl.hadoop.udf;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.hadoop.hive.ql.exec.UDAF;
import org.apache.hadoop.hive.ql.exec.UDAFEvaluator;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;

@SuppressWarnings("deprecation")
public class TopNUDAF extends UDAF{

	public static class State{
		ArrayList
   
   
    
     a;//保存topn的结果
		int n;//调用该函数的topN的N
		boolean ascending;//升序还是降序
	}
	
	public static class Evaluator implements UDAFEvaluator{
		private State state;
		public Evaluator(){
			init();
		}
		//初始化Evaluator对象
		public void init() {
			if(state == null){
				state = new State();
			}
			state.a = new ArrayList
    
    
     
     ();
			state.n = 0;
			state.ascending = false;//默认降序
		}
		/**
		 * map任务每行都会调用一次,iterate接收的参数正是调用函数时传入的参数
		 * @param other 聚合的字段值
		 * @param n topN的N
		 * @return
		 * @throws UDFArgumentException 
		 */
		public boolean iterate(Double other,int n,String asc) throws UDFArgumentException{
			//升降序topn表示,false表示最大值,true表示最小值
				if(asc == null || asc.equals("")){
					throw new UDFArgumentException("third argument like 'asc' or 'desc'");
				}
				if(!asc.equals("asc") && !asc.equals("desc")){
					throw new UDFArgumentException("third argument like 'asc' or 'desc'");
				}
				if(asc.equals("asc")){
					state.ascending = true;
				}
				state.n = n;
				if(other != null){
					//是否插入标示
					boolean doInsert = state.a.size() < n;
					//如果当前的state.a的元素数量小于n时则需要插入操作
					//如果当前的state.a的元素数量大于或者等于n时,则需要将数组中的最后一位与待插入的数进行比较
					//从而确定是否应该插入。
					if(!doInsert){
						Double last = state.a.get(state.a.size()-1);
						if(state.ascending){
							//当ascending为true时,即为升序,topN中即为最小的N位,因此只有待插入的数比最后一位小时,才会进行插入操作,否则直接返回
							doInsert = other < last;
						}else{
							//当ascending为false时,即为降序,topN中即为最大的N位,因此只有待插入的数比最后一位大时,才会进行插入操作,否则直接返回
							doInsert = other > last;
						}
					}
					if(doInsert){
						//有顺序的插入other的值
						binaryInsert(state.a,other,state.ascending);
						if(state.a.size() > n){
							state.a.remove(state.a.size()-1);
						}
					}
				}
			return true;
		}
		//将value得知按照ascending的顺序插入到list中相应的位置
		static 
     
     
      
      > void binaryInsert(List
      
      
       
        list, T value, boolean ascending){
			//根据顺序获取value在list中的位置,当list中没有元素的时候,则会返回-1,插入方法是先根据二分法进行查找,然后再插入
			int position = Collections.binarySearch(list, value, getComparator(ascending,(T)null));
			if(position < 0 ){
				position = (-position) - 1;
			}
			list.add(position,value);
		}
		//比较器
		static 
       
       
         > Comparator 
        
          getComparator(boolean ascending,T dummy){ Comparator 
         
           comp; if(ascending){ //如果是升序,谁小谁在前 comp = new Comparator 
          
            (){ public int compare(T o1,T o2){ return o1.compareTo(o2); } }; }else{ //如果是降序,谁大谁排在前 comp = new Comparator 
           
             (){ public int compare(T o1,T o2){ return o2.compareTo(o1); } }; } return comp; } //返回局部topN public State terminatePartial(){ if(state.a.size()>0){ return state; }else{ return null; } } /** * reduce端,将map的输出结果进行合并 * @param s 将要与当前State合并的State * @return */ public boolean merge(State s){ if(s != null){ state.n = s.n; state.a = sortedMerge(s.a,state.a,state.ascending,s.n); } return true; } static 
            
              > ArrayList 
             
               sortedMerge(List 
              
                list1,List 
               
                 list2,boolean ascending,int n){ Comparator 
                
                  comp = getComparator(ascending, (T)null); int n1 = list1.size(); int n2 = list2.size(); int p1 = 0;//当前list1的元素 int p2 = 0;//当前list2的元素 //保存结果,有n个元素 ArrayList 
                 
                   output = new ArrayList 
                  
                    (n); //遍历并将list1和list2归并到output 中,归并过程中保留output最多有n个元素 while(output.size() 
                   
                     terminate(){ if(state.a.size()>0){ return state.a; }else{ return null; } } } }


2、UDF

需求是将表中的日期格式转换成指定的模式:



package com.wangl.hadoop.udf;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

public class MyDateParse extends UDF{
	private Text result = new Text();
	
	//hive自定义函数,继承UDF之后,还需要定义一个evaluate方法
	public Text evaluate(Text str){
		String newStr = str.toString();
		//根据实际情况制定日期模式,根据字段的内容对字段进行转换
		SimpleDateFormat format = new SimpleDateFormat("dd/MMMMM/yyyy:HH:mm:ss Z", Locale.ENGLISH);
		if(str.toString().indexOf("[")>-1){
			newStr = newStr.replace("[", "");
		}
		if(str.toString().indexOf("]")>-1){
			newStr = newStr.replace("]", "");
		}
		try{
			Date date = format.parse(newStr);
			SimpleDateFormat newFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			result.set(newFormat.format(date));
			return result;
		}catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}



3、UDAF

需求是将表中的两个字段按照指定的分隔符进行连接



package com.wangl.hadoop.udf;

import java.util.ArrayList;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;

public class MergeFields extends GenericUDTF{
	
	String str1;
	String str2;
	Object[] forwardObj = null;
	@Override
	public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
		if(argOIs.length!=2){
			throw new UDFArgumentException("参数异常");
		}
		//初始化输入输出的格式
		forwardObj = new Object[1];
		str1 = ((StringObjectInspector)argOIs[0]).getPrimitiveJavaObject(argOIs[0]);
		str2 = ((StringObjectInspector)argOIs[1]).getPrimitiveJavaObject(argOIs[1]);
		ArrayList
      
      
       
        fieldNames = new ArrayList
       
       
        
        ();
		ArrayList
        
        
         
          fieldOIs = new ArrayList
         
         
          
          ();
		
		fieldNames.add("rcol1");
		fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
		//指定输出的字段名称和输出内容格式
		return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
	}
	/**
	 * 这里只是对两个字段进行连接,主要是了解如何自定义UDTF的方法
	 */
	@Override
	public void process(Object[] args) throws HiveException {
		forwardObj[0] = str1 +"---"+ str2;
		
 		forward(forwardObj);
	}

	@Override
	public void close() throws HiveException {
		// TODO Auto-generated method stub
		
	}
	
}






以上的代码仅供参考,如有问题欢迎指出。