为了满足用户的个性化需求,Hive被设计成了一个很开放的系统,很多内容都可以定制,主要包括:
1)、文件格式;
2)、内存中的数据格式,如Hadoop的Writable/Text;
3)、用户提供的MapReduce脚本,不管使用何种语言都可以通过标准的stdin/stdout传输数据;
4)、用户自定义函数。
本节我们主要学习用户自定义函数。虽然Hive已经提供了很多内存的函数,但是还是不能,满足用户的需求,因此有提供了自定义函数供用户自己开发函数来满足自己的需求。之定义函数主要分三类:
1)、UDF(User-Defined-Function)用户自定义函数,输入一个数据然后产生一个数据;
2)、UDAF(User-Defined Aggregation Function)用户自定义聚合函数,多个输入数据然后产生一个输出参数;
3)、UDTF(User-Defined Table-generating Function)用户自定义表生成函,数,输入一行数据生成N行数据。
UDF
现在我们开始学习如何来开发自己的UDF函数。假设我们现在有一个被保存在littlebigdata.txt文件中的数据集:
1. edward capriolo,edward@media6degrees.com,2-12-1981,209.191.139.200,M,10
2. bob,bob@test.net,10-10-2004,10.10.10.1,M,50
3. sara connor,sara@sky.net,4-5-1974,64.64.5.1,F,2
4. ...
接下来我们顶一个Hive加载这个数据集:
1. hive> CREATE TABLE IF NOT EXISTS littlebigdata(
2. '姓名',
3. '邮箱',
4. '生日',
5. 'ip',
6. '性别',
7. > anum INT)
8. ',';
9.
10. hive> LOAD DATA LOCAL INPATH '${env:HOME}/littlebigdata.txt'
11. > INTO TABLE littlebigdata;
我们接下来会写一个自定义的UDF根据数据集中的生日计算对应星座,首先新类要继承org.apache.hadoop.hive.ql.exec.UDF类,然而UDF类并不是一个抽象类,其中并没有用户自定义函数必须的evaluate()方法,子类必须实现一个或多个evaluate方法给Hive框架调用,这个evaluate方法正是所有实现类的逻辑部分所在,只有用户自己来写方法了:
1. package
2.
3. import
4. import
5. import
6. import
7.
8. @Description(name = "Zodiac",
9. "FUNC_(date) - from the input data string "
10. "or separate month and day arguments,return the sign of the Zodiac.",
11. "Example:\n >SELECT _FUNC_(date_string) FROM src;\n"
12. " > SELECT _FUNC_(month,day) FROM src;")
13. public class ZodiacSignUDF extends
14. private SimpleDateFormat df = null;
15.
16. /**
17. * 在默认构造函数中初始化df
18. */
19. public
20. new SimpleDateFormat("MM-dd-yyyy");
21. }
22.
23. /**
24. * 由出生日期获取星座
25. * @param birthday -Date
26. * @return
27. */
28. public
29. return this.evaluate(birthday.getMonth() + 1,birthday.getDay());
30. }
31.
32. /**
33. * 由出生日期获取星座
34. * @param birthday -String
35. * @return
36. */
37. public
38. null;
39. try{
40. date = df.parse(birthday);
41. catch(Excetion e){
42. //如果日期转换失败,就表明星座是未知的
43. return null;
44. }
45. return this.evaluate(date.getMonth() + 1,date.getDay());
46. }
47.
48. /**
49. * 由月份和出生日获取星座
50. * @param month -int
51. * @param day -int
52. * @return
53. */
54. public
55. if(month == 1){
56. if(day < 20){
57. return "Capricorn";
58. else{
59. return "Aquarius";
60. }
61. else if(month == 2){
62. if(day < 19){
63. return "Aquarius";
64. else{
65. return "Pisces";
66. }
67. }
68. /** ... other months here */
69. return null;
70. }
71. }
在HiveQL的执行中,没处理一行都会调用一次ZodiacSignUDF类的实例,然后将每一行的出生一起传给evaluate()方法并得到对应的星座返回给Hive。
那么接下来的问题是如何使用这个自定义函数呢?
首先需要用户便以这个类并将之打成一个jar包,然后将jar文件添加到Hive的classpath并使用CREATE FUNCTION语句将之定义为一个Hive能使用的方法:
1. hive> ADD JAR /full/path/to/zodiac.jar;
2. hive> CREATE TEMPORARY FUNCTION zodiac
3. 'org.apache.hadoop.hive.contrib.udf.exampl.ZodiacSignUDF';
当然,上面的函数添加方法只能在Hive session会话期间使用,session结束后如还想使用该函数,那就必须再将上面的两部操作做一遍。如果这个函数是经常使用的,那么这么做就太繁琐了,这种情况下可以把上面的两操作语句添加到$HOME/.hiverc文件中作为全局函数,就想使用hive的内置行是一样:
1. hive> SELECT name,birthday,zodiac(birthday) FROM littlebigdata;
2. edward capriolo 2-12-1981
3. bob 10-10-2004
4. sara 4-5-1974
接着我们来看怎么删除一个·自定义函数:
hive> DROP TEMPORARY FUNCTION IF EXISTS zodiac;
http://flyingdutchman.iteye.com/blog/1871326
HIVE如何使用自定义函数
HIVE提供了很多函数,但这些函数只能满足一般的需求,针对复杂的业务分析,需要自己开发适合业务需求的函数。如何开发HIVE的UDF/UDAF/UDTF,请参看如下博客介绍的自定义函数的模板: http://hugh-wangp.iteye.com/blog/1472371
如何在HIVE中使用自己定义的函数,可以有几种方式:
1.在HIVE会话中add 自定义函数的jar文件,然后创建function,继而使用函数
2.在进入HIVE会话之前先自动执行创建function,不用用户手工创建
3.把自定义的函数写到系统函数中,使之成为HIVE的一个默认函数,这样就不需要create temporary function
1.在HIVE会话中add 自定义函数的jar文件,然后创建function,继而使用函数
hive> ADD JAR /home/hugh.wangp/UDFMd5.jar;
Added /home/hugh.wangp/UDFMd5.jar to class path
hive> CREATE TEMPORARY FUNCTION udfmd5 AS 'udf.UDFMd5';
OK
Time taken: 0.014 seconds
hive> select udfmd5('a') from dual;
OK
0cc175b9c0f1b6a831c399e269772661
这种方式的弊端是:每次打开新的会话,就要重新执行一遍如上的add jar和create temporary function的命令。对普通的业务分析人员未免要求太高。第二种方法可以把业务人员释放出来
2.在进入HIVE会话之前先自动执行创建function
HIVE命令有个参数-i:在进入会话,待用户输入自己的HQL之前,先执行-i的参数。我们只需要把add jar和create temporary function的命令写到一个文件中,并把这个文件传到-i的参数,如此一来省去了每次要手工创建的工作。
但是这种方式也有个弊端,当我增添HIVE的gateway,就要拷贝一份这个文件,有时候遗漏真是不可避免的。第三种方法应该就是一个终极方案,只要HIVE本身代码不做修改,或者不删除特定的功能,这个函数就能一直用,而且可以把他作为HIVE的默认函数那样使用
3.把自定义的函数写到系统函数中,使之成为HIVE的一个默认函数
a.编写自己的UDF/UDAF/UDTF(如何编写可参考:http://hugh-wangp.iteye.com/blog/1472371),并把代码放到$HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/udf/路径下
b.修改$HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java
以HIVE自带函数Trim()举例,自定义函数操作一样。
第一步:
写UDF代码UDFTrim.java并放到$HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/udf/UDFTrim.java
第二步:修改$HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java文件
a.import org.apache.hadoop.hive.ql.udf.UDFTrim;
b.registerUDF("trim", UDFTrim.class, false);
虽然这种方法是一劳永逸的方法,但是一旦错了,对整个HIVE使用都是灾难性的,所以不是特别通用的自定义函数还是采用前两种,一旦通用的自定义函数累计到一定程度,再去采用第三种方法。