Hive开发UDF
从无到有开发hive的udf,本篇不针对简单的,针对复杂参数
移除点击此处添加图片说明文字
目录:
add jar /opt/workspace/udf/GetAppUDF.jar;
小坑,路径一定要写对,之前出现文件找不到,我以为要放到hdfs上面呢。
[[email protected] root]$ hadoop fs -mkdir /user/hive/warehouse/udf
[[email protected] root]$ hadoop fs -put /opt/workspace/udf/GetAppUDF-1.0.jar /user/hive/warehouse/udf/GetAppUDF.jar
后来及时悬崖勒马。
创建临时函数:
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
哦,原来是jdk版本有问题啊。
本机是最新版,看下服务器的,
嗯,1.7.0_55的,咱们要去安装一下了。
安装
等一下进度
然后咱们remove换一下jdk
搞定之后,重新打包吧。
然后发布,还是这个玩意:
好难受呀。
然后咱们换第三个,1.7.0.88次修改,第三次装jdk好了,报另一个错了。
解决了这个问题了,还是蛮开心的。
咱们再:
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
create temporary function GetAppUDF as ' com.test.Hive.udf.GetAppUDF ';
总是报错:FAILED: Class com.test.Hive.udf.GetAppUDF not found
后来我发现了,乱倒腾发现的。
那我们把他重新打印一遍:
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
然后我们运行
我靠,然后我desc safedata.apk_use
发现
array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>
这种格式的字段,我第一次见到。
然后咱们查资料发现这么个东西:
暂且理解为全部强制性读进来。
但是这回报错:
这个到底是怎么回事呢?
原来是因为我们复制了很多>
那好,我们把>删掉,重来。
select uuid,GetAppUDF(apk_use),pt from safedata.apk_use limit 100;
结果:
FAILED: SemanticException [Error 10014]: Line 3:1 Wrong arguments 'apk_use': No matching method for class com.test.Hive.udf.GetAppUDF with (array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>). Possible choices: _FUNC_(string)
原因就是这个格式,很恶心, array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>
卡了很久,怎么办呢。
卡住了很久,我感觉要来个狠得。请看
结果气得想吐学:
java也这么蠢啊,好难受,妈的。
去网上找大神操作吧。
还是老样子,卡在这里快一到两个小时了,问了一下老大,他也不知道,让我研究。那好吧,继续研究吧。
我们看一篇文章:
Hive中,除了提供丰富的内置函数(见[一起学Hive]之二–Hive函数大全-完整版)之外,还允许用户使用Java开发自定义的UDF函数。
开发自定义UDF函数有两种方式,一个是继承org.apache.hadoop.hive.ql.exec.UDF,另一个是继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
如果是针对简单的数据类型(比如String、Integer等)可以使用UDF,如果是针对复杂的数据类型(比如Array、Map、 Struct等),可以使用GenericUDF,另外,GenericUDF还可以在函数开始之前和结束之后做一些初始化和关闭的处理操作。
UDF
使用UDF非常简单,只需要继承org.apache.hadoop.hive.ql.exec.UDF,并定义
public Object evaluate(Object args) {} 方法即可。
比如,下面的UDF函数实现了对一个String类型的字符串取HashMD5:
- package com.lxw1234.hive.udf;
- import org.apache.hadoop.hbase.util.Bytes;
- import org.apache.hadoop.hbase.util.MD5Hash;
- import org.apache.hadoop.hive.ql.exec.UDF;
- public class HashMd5 extends UDF {
- public String evaluate(String cookie) {
- return MD5Hash.getMD5AsHex(Bytes.toBytes(cookie));
- }
- }
将上面的HashMd5类打成jar包,udf.jar
使用时候,在Hive命令行执行:
- add jar file:///tmp/udf.jar;
- CREATE temporary function str_md5 as 'com.lxw1234.hive.udf.HashMd5';
- select str_md5(‘lxw1234.com’) from dual;
具体文章我粘贴一下地址:
http://www.cnblogs.com/1130136248wlxk/articles/5519276.html
GenericUDF
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF之后,需要重写几个重要的方法:
publicvoid configure(MapredContext context) {}
//可选,该方法中可以通过context.getJobConf()获取job执行时候的Configuration;
//可以通过Configuration传递参数值
public ObjectInspector initialize(ObjectInspector[] arguments)
//必选,该方法用于函数初始化操作,并定义函数的返回值类型;
//比如,在该方法中可以初始化对象实例,初始化数据库链接,初始化读取文件等;
public Object evaluate(DeferredObject[] args){}
//必选,函数处理的核心方法,用途和UDF中的evaluate一样;
public String getDisplayString(String[] children)
//必选,显示函数的帮助信息
public void close(){}
//可选,map完成后,执行关闭操作
所以我们新写一个类吧。
然后我们改写之后,出现:
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF2';
select uuid,GetAppUDF(apk_use),pt from safedata.apk_use limit 100;
但是,我们看到还是这个问题啊、
Exception in thread "main" java.lang.NoClassDefFoundError: net/sf/json/JSONArray
那接下来该怎么办,只能重新想办法了。
后来我想到了一个好的点子,卡了一整个下午,我就在向着怎么会找不到json类,一个原因是真的转不了,还有一个可能就是,根本没有接收到参数,所以空,也会报这个错。那么我换个巧妙地方式,你不是要微博的数据吗。那我这样。
可以,很巧妙,发布试一下:
那我们把object换成String把。重新发布。
但是:Failed with exception java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;
这个其实就是转换错误的,我们看看程序吧。
我靠你大爷的,改了好久好久我的天:
卡了太久了。受不了了。然后我思考了很久,发现了这个代码
细心的发现了这个是list,我靠,坑啊,血坑。
//return ObjectInspectorFactory.getStandardListObjectInspector(returnOI);
return returnOI;
给力了。我的哥。
好了,接下来开发。
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF2';
drop table testing.testweiboudf;
create table testing.testWeiboUDF as select im,is,uuid,GetAppUDF(apk_list) ifWeibo,dt,pt from safedata.apk_list where apk_list is not null;
好像有不少任务,
等到hive转化的mapreduce跑完了,就可以了。
然后我们发现全量表切割后,字段全部为false。
那简单,我们换一个应用试一试,换唯品会吧,或者是别的什么的。
如果换成“微博”还不行,要么就是utf-8的事情,要么,就真的没有微博,接下来就换别的试试了,没有办法了。只能如此。等等跑完了看看吧,这个udf有点恶心。
这就很尴尬了,我们换一个。看看到底怎么回事。然后我试了一试别的,发现怎么都是false,这就有问题了。
这个中间报了个这么错:
因为是那种特殊数组格式,我们得加一个is not null
改好了之后,还是这样,算了,先告一段落吧,下午要开发python爬虫了,没时间搞这个了,先停一段落吧。等这周后期,咱们再整这个吧,现在就差一点点了。后面如果有时间我们再把这个array<struct<>>解析一下吧。
其实简单的udf很好写,就是重写一个 evaluate函数,然后用参数取得字段值,分解,复杂的这个,继承GenericUDF,重写三个方法,initialize、evaluate、getdisplayString
目录:
add jar /opt/workspace/udf/GetAppUDF.jar;
小坑,路径一定要写对,之前出现文件找不到,我以为要放到hdfs上面呢。
[[email protected] root]$ hadoop fs -mkdir /user/hive/warehouse/udf
[[email protected] root]$ hadoop fs -put /opt/workspace/udf/GetAppUDF-1.0.jar /user/hive/warehouse/udf/GetAppUDF.jar
后来及时悬崖勒马。
创建临时函数:
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
哦,原来是jdk版本有问题啊。
本机是最新版,看下服务器的,
嗯,1.7.0_55的,咱们要去安装一下了。
安装
等一下进度
然后咱们remove换一下jdk
搞定之后,重新打包吧。
然后发布,还是这个玩意:
好难受呀。
然后咱们换第三个,1.7.0.88次修改,第三次装jdk好了,报另一个错了。
解决了这个问题了,还是蛮开心的。
咱们再:
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
create temporary function GetAppUDF as ' com.test.Hive.udf.GetAppUDF ';
总是报错:FAILED: Class com.test.Hive.udf.GetAppUDF not found
后来我发现了,乱倒腾发现的。
那我们把他重新打印一遍:
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF';
然后我们运行
我靠,然后我desc safedata.apk_use
发现
array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>
这种格式的字段,我第一次见到。
然后咱们查资料发现这么个东西:
暂且理解为全部强制性读进来。
但是这回报错:
这个到底是怎么回事呢?
原来是因为我们复制了很多>
那好,我们把>删掉,重来。
select uuid,GetAppUDF(apk_use),pt from safedata.apk_use limit 100;
结果:
FAILED: SemanticException [Error 10014]: Line 3:1 Wrong arguments 'apk_use': No matching method for class com.test.Hive.udf.GetAppUDF with (array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>). Possible choices: _FUNC_(string)
原因就是这个格式,很恶心, array<struct<apk:string,n:string,v:string,v_n:string,c:int,t:int>>
卡了很久,怎么办呢。
卡住了很久,我感觉要来个狠得。请看
结果气得想吐学:
java也这么蠢啊,好难受,妈的。
去网上找大神操作吧。
还是老样子,卡在这里快一到两个小时了,问了一下老大,他也不知道,让我研究。那好吧,继续研究吧。
我们看一篇文章:
Hive中,除了提供丰富的内置函数(见[一起学Hive]之二–Hive函数大全-完整版)之外,还允许用户使用Java开发自定义的UDF函数。
开发自定义UDF函数有两种方式,一个是继承org.apache.hadoop.hive.ql.exec.UDF,另一个是继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
如果是针对简单的数据类型(比如String、Integer等)可以使用UDF,如果是针对复杂的数据类型(比如Array、Map、 Struct等),可以使用GenericUDF,另外,GenericUDF还可以在函数开始之前和结束之后做一些初始化和关闭的处理操作。
UDF
使用UDF非常简单,只需要继承org.apache.hadoop.hive.ql.exec.UDF,并定义
public Object evaluate(Object args) {} 方法即可。
比如,下面的UDF函数实现了对一个String类型的字符串取HashMD5:
- package com.lxw1234.hive.udf;
- import org.apache.hadoop.hbase.util.Bytes;
- import org.apache.hadoop.hbase.util.MD5Hash;
- import org.apache.hadoop.hive.ql.exec.UDF;
- public class HashMd5 extends UDF {
- public String evaluate(String cookie) {
- return MD5Hash.getMD5AsHex(Bytes.toBytes(cookie));
- }
- }
将上面的HashMd5类打成jar包,udf.jar
使用时候,在Hive命令行执行:
- add jar file:///tmp/udf.jar;
- CREATE temporary function str_md5 as 'com.lxw1234.hive.udf.HashMd5';
- select str_md5(‘lxw1234.com’) from dual;
具体文章我粘贴一下地址:
http://www.cnblogs.com/1130136248wlxk/articles/5519276.html
GenericUDF
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDF之后,需要重写几个重要的方法:
publicvoid configure(MapredContext context) {}
//可选,该方法中可以通过context.getJobConf()获取job执行时候的Configuration;
//可以通过Configuration传递参数值
public ObjectInspector initialize(ObjectInspector[] arguments)
//必选,该方法用于函数初始化操作,并定义函数的返回值类型;
//比如,在该方法中可以初始化对象实例,初始化数据库链接,初始化读取文件等;
public Object evaluate(DeferredObject[] args){}
//必选,函数处理的核心方法,用途和UDF中的evaluate一样;
public String getDisplayString(String[] children)
//必选,显示函数的帮助信息
public void close(){}
//可选,map完成后,执行关闭操作
所以我们新写一个类吧。
然后我们改写之后,出现:
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF2';
select uuid,GetAppUDF(apk_use),pt from safedata.apk_use limit 100;
但是,我们看到还是这个问题啊、
Exception in thread "main" java.lang.NoClassDefFoundError: net/sf/json/JSONArray
那接下来该怎么办,只能重新想办法了。
后来我想到了一个好的点子,卡了一整个下午,我就在向着怎么会找不到json类,一个原因是真的转不了,还有一个可能就是,根本没有接收到参数,所以空,也会报这个错。那么我换个巧妙地方式,你不是要微博的数据吗。那我这样。
可以,很巧妙,发布试一下:
那我们把object换成String把。重新发布。
但是:Failed with exception java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;
这个其实就是转换错误的,我们看看程序吧。
我靠你大爷的,改了好久好久我的天:
卡了太久了。受不了了。然后我思考了很久,发现了这个代码
细心的发现了这个是list,我靠,坑啊,血坑。
//return ObjectInspectorFactory.getStandardListObjectInspector(returnOI);
return returnOI;
给力了。我的哥。
好了,接下来开发。
add jar /opt/workspace/udf/GetAppUDF.jar;
create temporary function GetAppUDF as 'com.test.Hive.udf.GetAppUDF2';
drop table testing.testweiboudf;
create table testing.testWeiboUDF as select im,is,uuid,GetAppUDF(apk_list) ifWeibo,dt,pt from safedata.apk_list where apk_list is not null;
好像有不少任务,
等到hive转化的mapreduce跑完了,就可以了。
然后我们发现全量表切割后,字段全部为false。
那简单,我们换一个应用试一试,换唯品会吧,或者是别的什么的。
如果换成“微博”还不行,要么就是utf-8的事情,要么,就真的没有微博,接下来就换别的试试了,没有办法了。只能如此。等等跑完了看看吧,这个udf有点恶心。
这就很尴尬了,我们换一个。看看到底怎么回事。然后我试了一试别的,发现怎么都是false,这就有问题了。
这个中间报了个这么错:
因为是那种特殊数组格式,我们得加一个is not null
改好了之后,还是这样,算了,先告一段落吧,下午要开发python爬虫了,没时间搞这个了,先停一段落吧。等这周后期,咱们再整这个吧,现在就差一点点了。后面如果有时间我们再把这个array<struct<>>解析一下吧。
其实简单的udf很好写,就是重写一个 evaluate函数,然后用参数取得字段值,分解,复杂的这个,继承GenericUDF,重写三个方法,initialize、evaluate、getdisplayString