UDF函數開發
標准函數(UDF):以一行數據中的一列或者多列數據作為參數然后返回解雇歐式一個值的函數,同樣也可以返回一個復雜的對象,例如array,map,struct。
聚合函數(UDAF):接受從零行到多行的零個到多個列,然后返回單一值。例如sum函數。
生成函數(UDTF):接受零個或者多個輸入,然后產生多列或者多行輸出。
udf函數開發
當Hive提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數,用戶自定義函數(user defined function),針對單條記錄。編寫一個UDF,需要繼承UDF類,並實現evaluate()函數。在查詢執行過程中,查詢中對應的每個應用到這個函數的地方都會對這個類進行實例化。對於每行輸入都會調用到evaluate()函數。而evaluate()函數處理的值會返回給Hive。同時用戶是可以重載evaluate方法的。Hive會像Java的方法重載一樣,自動選擇匹配的方法。
准備數據:
littlebigdata.txt
edward capriolo,edward@media6degrees.com,2-12-1981,209.191.139.200,M,10 bob,bob@test.net,10-10-2004,10.10.10.1,M,50 sara connor,sara@sky.net,4-5-1974,64.64.5.1,F,2
創建表:
create table if not exists littlebigdata( name string, email string, bday string, ip string, gender string, anum int ) row format delimited fields terminated by ',';
加載數據:
load data local inpath 'littlebigdata.txt' into table littlebigdata;
代碼示例:

import java.text.SimpleDateFormat; import java.util.Date; import org.apache.hadoop.hive.ql.exec.UDF; import org.junit.Test; public class UDFZodiacSign extends UDF { private SimpleDateFormat df ; public UDFZodiacSign() { df = new SimpleDateFormat("MM-dd-yyyy"); } public String evaluate(Date bday){ return evaluate(bday.getMonth(),bday.getDay()); } public String evaluate(String bday){ Date date =null; try{ date = df.parse(bday); } catch(Exception ex){ System.out.println("異常"); ex.printStackTrace(); return null; } return evaluate(date.getMonth()+1,date.getDay()); } public String evaluate(Integer month,Integer day){ if(month ==1){ if(day<20){ return "Capricorn"; }else{ return "Aquarius"; } } if(month ==2){ if(day<19){ return "Capricorn"; }else{ return "Pisces"; } } if(month ==3){ if(day<20){ return "Pisces"; }else{ return "Aries"; } } if(month ==4){ if(day<20){ return "Aries"; }else{ return "Taurus"; } } if(month ==5){ if(day<20){ return "Taurus"; }else{ return "Gemini"; } } if(month ==6){ if(day<21){ return "Gemini"; }else{ return "Cancer"; } } if(month ==7){ if(day<22){ return "Cancer"; }else{ return "Leo"; } } if(month ==8){ if(day<23){ return "Leo"; }else{ return "Virgo"; } } if(month ==9){ if(day<22){ return "Virgo"; }else{ return "Libra"; } } if(month ==10){ if(day<24){ return "Libra"; }else{ return "Scorpio"; } } if(month ==11){ if(day<22){ return "Scorpio"; }else{ return "Sagittarius"; } } if(month ==12){ if(day<22){ return "Sagittarius"; }else{ return "Capricorn"; } } return null; } @Test public void test() { UDFZodiacSign aa = new UDFZodiacSign(); String str = aa.evaluate("01-10-2004"); System.out.println(str); } }
函數使用
加載:
add jar testUDF-0.0.1-SNAPSHOT.jar; create temporary function zodiac as "cn.rtmap.bigdata.hive.testUDF.udf.UDFZodiacSign";
查詢:
select name,bday,zodiac(bday) from littlebigdata;
結果:
edward capriolo 2-12-1981 Capricorn bob 10-10-2004 Libra sara connor 4-5-1974 Aries
注意:這個地方可能有報錯,反正我是遇到了!
解決辦法:
1,修改jdk的版本 可能版本太高。
2,刪除META-INF 文件中*.SF的文件,這個是依賴包有沖突導致的。
3.在MANIFEST.MF 中添加Main-Class: cn.rtmap.bigdata.hive.testUDF.udf.UDFZodiacSign,這個可以在maven中創建好。
UDF四種加載方式
第一種:
是最常見但也不招人喜歡的方式是使用ADD JAR(s)語句,之所以說是不招人喜歡是,通過該方式添加的jar文件只存在於當前會話中,當會話關閉后不能夠繼續使用該jar文件,最常見的問題是創建了永久函數到metastore中,再次使用該函數時卻提示ClassNotFoundException。所以使用該方式每次都要使用ADD JAR(s)語句添加相關的jar文件到Classpath中。
第二種:
是修改hive-site.xml文件。修改參數hive.aux.jars.path的值指向UDF文件所在的路徑。,該參數需要手動添加到hive-site.xml文件中。
<property> <name>hive.aux.jars.path</name> <value>file:///jarpath/all_new1.jar,file:///jarpath/all_new2.jar</value> </property>
第三種:
是在${HIVE_HOME}下創建auxlib目錄,將UDF文件放到該目錄中,這樣hive在啟動時會將其中的jar文件加載到classpath中。(推薦)
第四種:
是設置HIVE_AUX_JARS_PATH環境變量,變量的值為放置jar文件的目錄,可以拷貝${HIVE_HOME}/conf中的hive-env.sh.template為hive-env.sh文件,並修改最后一行的#export HIVE_AUX_JARS_PATH=為exportHIVE_AUX_JARS_PATH=jar文件目錄來實現,或者在系統中直接添加HIVE_AUX_JARS_PATH環境變量。