hive UDF 自定函数

今天有同事来问一个我写过的UDF的问题,想起之前貌似写过一篇这样的文章,草稿箱里找了下,确实有,躺了一年半了,发出来,也许对某些同学有帮助~


HIVE允许用户使用UDF(user defined function)对数据进行处理。
用户可以使用‘show functions’ 查看function list,可以使用'describe function function-name'查看函数说明。
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. hive> show functions;  
  2. OK  
  3. !  
  4. !=  
  5. ......  
  6. Time taken: 0.275 seconds  
  7. hive> desc function substr;  
  8. OK  
  9. substr(str, pos[, len]) - returns the substring of str that starts at pos and is of length len orsubstr(bin, pos[, len]) - returns the slice of byte array that starts at pos and is of length len  
  10. Time taken: 0.095 seconds  

hive提供的build-in函数包括以下几类:
1. 关系操作符:包括 = 、 <> 、 <= 、>=等
2. 算数操作符:包括 + 、 - 、 *、/等
3. 逻辑操作符:包括AND 、 && 、 OR 、 || 等
4. 复杂类型构造函数:包括map、struct、create_union等
5. 复杂类型操作符:包括A[n]、Map[key]、S.x
6. 数学操作符:包括 ln(double a)、sqrt(double a)等
7. 集合操作符:包括 size(Array<T>)、sort_array(Array<T>)等
8. 类型转换函数:  binary(string|binary)、cast(expr as <type>)
9. 日期函数:包括 from_unixtime(bigint unixtime[, string format])、unix_timestamp()等
10.条件函数:包括 if(boolean testCondition, T valueTrue, T valueFalseOrNull)等
11. 字符串函数:包括 a cat(string|binary A, string|binary B...)等
12. 其他:xpath、get_json_object scii(string str)、con

编写Hive UDF有两种方式:
1. extends UDF , 重写evaluate方法
2. extends GenericUDF,重写initialize、getDisplayString、evaluate方法


编写UDF代码实例 (更多例子参考 https://svn.apache.org/repos/asf/hive/tags/release-0.8.1/ql/src/java/org/apache/hadoop/hive/ql/udf/ ):
功能:大小转小写
ToLowerCase.java:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package test.udf;  
  2.   
  3. import org.apache.hadoop.hive.ql.exec.UDF;  
  4. import org.apache.hadoop.io.Text;  
  5.   
  6. public class ToLowerCase extends UDF {  
  7.     public Text evaluate(final Text s) {  
  8.         if (s == null) { return null; }  
  9.         return new Text(s.toString().toLowerCase());  
  10.     }  
  11. }  

功能:计算array中去重后元素个数
UDFArrayUniqElementNumber .java

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package test.udf;  
  2. import org.apache.hadoop.hive.ql.exec.Description;  
  3. import org.apache.hadoop.hive.ql.exec.UDFArgumentException;  
  4. import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;  
  5. import org.apache.hadoop.hive.ql.metadata.HiveException;  
  6. import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;  
  7. import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector;  
  8. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;  
  9. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorUtils;  
  10. import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;  
  11. import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;  
  12. import org.apache.hadoop.io.IntWritable;  
  13.   
  14. /** 
  15.  * UDF: 
  16.  * Get nubmer of objects with duplicate elements eliminated 
  17.  * @author xiaomin.zhou 
  18.  */  
  19. @Description(name = "array_uniq_element_number", value = "_FUNC_(array) - Returns nubmer of objects with duplicate elements eliminated.", extended = "Example:\n"  
  20.                 + "  > SELECT _FUNC_(array(1, 2, 2, 3, 3)) FROM src LIMIT 1;\n" + "  3")  
  21. public class UDFArrayUniqElementNumber extends GenericUDF {  
  22.   
  23.         private static final int ARRAY_IDX = 0;  
  24.         private static final int ARG_COUNT = 1// Number of arguments to this UDF  
  25.         private static final String FUNC_NAME = "ARRAY_UNIQ_ELEMENT_NUMBER"// External Name  
  26.   
  27.         private ListObjectInspector arrayOI;  
  28.         private ObjectInspector arrayElementOI;  
  29.         private final IntWritable result = new IntWritable(-1);  
  30.   
  31.         public ObjectInspector initialize(ObjectInspector[] arguments)  
  32.                         throws UDFArgumentException {  
  33.   
  34.                 // Check if two arguments were passed  
  35.                 if (arguments.length != ARG_COUNT) {  
  36.                         throw new UDFArgumentException("The function " + FUNC_NAME  
  37.                                         + " accepts " + ARG_COUNT + " arguments.");  
  38.                 }  
  39.   
  40.                 // Check if ARRAY_IDX argument is of category LIST  
  41.                 if (!arguments[ARRAY_IDX].getCategory().equals(Category.LIST)) {  
  42.                         throw new UDFArgumentTypeException(ARRAY_IDX, "\""  
  43.                                         + org.apache.hadoop.hive.serde.Constants.LIST_TYPE_NAME  
  44.                                         + "\" " + "expected at function ARRAY_CONTAINS, but "  
  45.                                         + "\"" + arguments[ARRAY_IDX].getTypeName() + "\" "  
  46.                                         + "is found");  
  47.                 }  
  48.   
  49.                 arrayOI = (ListObjectInspector) arguments[ARRAY_IDX];  
  50.                 arrayElementOI = arrayOI.getListElementObjectInspector();  
  51.   
  52.                 return PrimitiveObjectInspectorFactory.writableIntObjectInspector;  
  53.         }  
  54.   
  55.         public IntWritable evaluate(DeferredObject[] arguments)  
  56.                         throws HiveException {  
  57.   
  58.                 result.set(0);  
  59.   
  60.                 Object array = arguments[ARRAY_IDX].get();  
  61.                 int arrayLength = arrayOI.getListLength(array);  
  62.                 if (arrayLength <= 1) {  
  63.                         result.set(arrayLength);  
  64.                         return result;  
  65.                 }  
  66.   
  67.                 //element compare; Algorithm complexity: O(N^2)  
  68.                 int num = 1;   
  69.                 int i, j;   
  70.                 for(i = 1; i < arrayLength; i++)  
  71.                 {  
  72.                         Object listElement = arrayOI.getListElement(array, i);  
  73.                         for(j = i - 1; j >= 0; j--)  
  74.                         {  
  75.                                 if (listElement != null) {  
  76.                                         Object tmp = arrayOI.getListElement(array, j);  
  77.                                         if (ObjectInspectorUtils.compare(tmp, arrayElementOI, listElement,  
  78.                                                         arrayElementOI) == 0) {  
  79.                                                 break;  
  80.                                         }  
  81.                                 }  
  82.                         }  
  83.                         if(-1 == j)  
  84.                         {  
  85.                                 num++;  
  86.                         }  
  87.                 }  
  88.   
  89.                 result.set(num);  
  90.                 return result;  
  91.         }  
  92.   
  93.         public String getDisplayString(String[] children) {  
  94.                 assert (children.length == ARG_COUNT);  
  95.                 return "array_uniq_element_number(" + children[ARRAY_IDX]+ ")";  
  96.         }  
  97. }  

生成udf.jar

hive有三种方法使用自定义的UDF函数
1. 临时添加UDF

如下:
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. hive> select * from test;     
  2. OK  
  3. Hello  
  4. wORLD  
  5. ZXM  
  6. ljz  
  7. Time taken: 13.76 seconds  
  8. hive> add jar /home/work/udf.jar;                                
  9. Added /home/work/udf.jar to class path  
  10. Added resource: /home/work/udf.jar  
  11. hive> create temporary function mytest as 'test.udf.ToLowerCase';  
  12. OK  
  13. Time taken: 0.103 seconds  
  14. hive> show functions;  
  15. ......  
  16. mytest  
  17. ......  
  18. hive> select mytest(test.name) from test;  
  19. ......  
  20. OK  
  21. hello  
  22. world  
  23. zxm  
  24. ljz  
  25. Time taken: 38.218 seconds  
这种方式在会话结束后,函数自动销毁,因此每次打开新的会话,都需要重新add jar并且create temporary function

2. 进入会话前自动创建
使用hive -i参数在进入hive时自动初始化
[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. $ cat hive_init   
  2. add jar /home/work/udf.jar;  
  3. create temporary function mytest as 'test.udf.ToLowerCase';  
  4. $ hive -i hive_init   
  5. Logging initialized using configuration in file:/home/work/hive/hive-0.8.1/conf/hive-log4j.properties  
  6. Hive history file=/tmp/work/hive_job_log_work_201209200147_1951517527.txt  
  7. hive> show functions;  
  8. ......  
  9. mytest  
  10. ......  
  11. hive> select mytest(test.name) from test;  
  12. ......  
  13. OK  
  14. hello  
  15. world  
  16. zxm  
  17. ljz  
方法2和方法1本质上是相同的,区别在于方法2在会话初始化时自动完成

3. 自定义UDF注册为hive内置函数
可参考:hive利器  自定义UDF+重编译hive

和前两者相比,第三种方式直接将用户的自定义函数作为注册为内置函数,未来使用起来非常简单,但这种方式也非常危险,一旦出错,将是灾难性的,因此,建议如果不是特别通用,并且固化下来的函数,还是使用前两种方式比较靠谱。


Reference:

How to write a Hive UDF

版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值