在Hive中创建使用自定义函数

原文地址:http://wenku.baidu.com/link?url=fz-k6QR_cUyAIMybchXZ42hj4a6-q3CsT79Ub8OOxF5WFPvKJwGJpXiUKEkurrWK3imAlXDDpGu7fHRzwX2GFtiIKLlVHBl9qzHqGFMzma

在Hive中创建使用自定义函数 
1 实际情况 
2 网传的四种做法 
2 适宜做法 
3 原理(hive源代码) 
4 实际情况    
Hive提供了不少的函数,但是针对比较复杂的业务,还需要我们手动去定义一些函数来进行一些数据分析处理。Hive的自定义函数包括UDF、UDAF和UDTF,
定义模板请参考 http://hugh-wangp.iteye.com/blog/1472371。  
网传的四种做法  
1. 在HIVE会话中add 自定义函数的jar文件,然后创建function,继而使用函数; 
2. 在进入HIVE会话之前先自动执行创建function,不用用户手工创建;  
3. 把自定义的函数写到系统函数中,使之成为HIVE的一个默认函数,这样就不需要 create temporary function;  
4. 在HIVE_HOME的bin目录下新建一个.hiverc的文件,把写好的注册语句写在里面。    
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的参数,如此一来省去了每次要手工创建的工作。    
3.把自定义的函数写到系统函数中,使之成为HIVE的一个默认函数
(1)编写自己的UDF/UDAF/UDTF,并把代码放到 $HIVE_HOME/src/ql/src/java/org/apache/hadoop/hive/ql/udf路径下
(2)修改 $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文件
import org.apache.hadoop.hive.ql.udf.UDFTrim; registerUDF("trim", UDFTrim.class, false);
小结:这样的好处在于通过直接修改源代码可以永久性的使用该函数,甚至不需要像第2种方法运行hive –i的命令了;
但是缺点也正在于此,要添加一个函数就需要修改源代码。   
4.在HIVE_HOME的bin目录下新建一个.hiverc的文件,把写好的注册语句写在里面 
在.hiverc文件中加入以下内容:
    ADD JAR /home/hugh.wangp/UDFMd5.jar;
    CREATE TEMPORARY FUNCTION udfmd5 AS 'udf.UDFMd5';  
小结:原理是,在运行./hive命令时,同时会加载HIVE_HOME/bin/.hiverc and $HOME/.hiverc作为初始化所需要的文件,
缺点是在不同机器的下运行时就要新建一个.hiverc文件,并且用jdbc连接时无效。
适宜做法  注:以下方法为针对IDH(transwarp也类似),且hive版本为0.9而言,
因为针对hive-0.13来说,有一种更为直接的方法: 
CREATE FUNCTION myfunc AS 'myclass' USING JAR 'hdfs:///path/to/jar'; 
这会将jar包直接加到classpath中去。详见: https://cwiki.apache.org/confluence/display/Hive/HivePlugins
(1)下载集群上的/usr/lib/hive/lib/hive-builtins-0.9.0-Intel.jar,解压得到如下文件:    
(2)编写自己的UDF/UDAF/UDTF,编译后将class文件(连同所在文件夹)放入到上面的hive-builtins-0.9.0-Intel文件夹下。 
 


(3)修改class-info.xml
 
   

根据自定义函数的情况在ClassList标签中添加(Javaname为自定义函数路径,sqlname为自定义函数名称),如:     
(4)修改class-registration.sql  CREATE TEMPORARY FUNCTION union_map AS 'org.apache.hive.builtins.UDAFUnionMap';
根据自定义函数的情况添加,保证函数名与第(3)步一致,如: CREATE TEMPORARY FUNCTION nextM AS 'udaf.AddOneMonth';
(5)重新将hive-builtins-0.9.0-Intel文件夹打jar包,并且上传到之前下载的目录覆盖旧jar包。
小结:这样做需要注意的是,你只能在你重新上传了新的jar包之后的那台机器上使用你自定义的hive函数,要是希望在集群的其他机器也可以使用,要拷贝该jar包到其他机器的相同目录下覆盖旧的jar包即可。
原理(hive源代码)
以下从hive的client连接开始,看hive的执行过程,仅考虑与上述“适宜做法”相关的部分代码——
Hive的client的入口(即执行hive命令后)为hive-cli-0.9.0-Intel.jar包中的org.apache.hadoop.hive.cli.CliDriver,
从main函数开始,初始化Hive环境变量,获取客户端提供的string或者file。
public static void main(String[] args) throws Exception {
int ret = run(args);
System.exit(ret);
}  
public static int run(String[] args) throws Exception {
OptionsProcessor oproc = new OptionsProcessor();
if (!oproc.process_stage1(args)) {
return 1;
}
// NOTE: It is critical to do this here so that log4j is reinitialized
// before any of the other core hive classes are loaded
boolean logInitFailed = false;
String logInitDetailMessage;
try { 
logInitDetailMessage = LogUtils.initHiveLog4j();
} catch (LogInitializationException e) {
logInitFailed = true;
logInitDetailMessage = e.getMessage();

CliSessionState ss = new CliSessionState(new HiveConf(SessionState.class));
...以下省略...  
上面的CliSessionState继承自SessionState,所以初始化时执行了SessionState的构造方法: 
public SessionState(HiveConf conf) {
this.conf = conf;
isSilent = conf.getBoolVar(HiveConf.ConfVars.HIVESESSIONSILENT);
ls = new LineageState();
overriddenConfigurations = new HashMap();
overriddenConfigurations.putAll(HiveConf.getConfSystemProperties());
// Register the Hive builtins jar and all of its functions
try {
Class pluginClass = Utilities.getBuiltinUtilsClass();
URL jarLocation = pluginClass.getProtectionDomain().getCodeSource().getLocation();//获取pluginclass所在jar包的路径 
add_builtin_resource(ResourceType.JAR, jarLocation.toString());
FunctionRegistry.registerFunctionsFromPluginJar(jarLocation, pluginClass.getClassLoader());
} catch (Exception ex) {
throw new RuntimeException("Failed to load Hive builtin functions", ex);
}   
}
至于上面粗线部分:
public static Class getBuiltinUtilsClass() throws ClassNotFoundException {
return Class.forName("org.apache.hive.builtins.BuiltinUtils");

而org.apache.hive.builtins.BuiltinUtils正在上面提到的 hive-builtins-0.9.0-Intel.jar当中。因此我们有了上面的“适宜做法”。

你可能感兴趣的:(hive)