hive開發UDF及使用
阿新 • • 發佈:2018-12-17
最近有個資料探勘的需求,要求統計所給經緯度附近n公里某些事物的數量。涉及到地球兩點間的距離計算,需要寫UDF進行計算。
一、UDF編寫
根據經緯度計算兩點間的距離,網上有很多計算方法,試了幾個,發現這篇部落格的方法計算的精度差比較小,他的分析方法也很詳細,最終採用此方法。
import com.ai.hive.udf.topdomain.StringUtil; import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.io.Text; import org.apache.log4j.Logger; /** * 功能:根據兩地經緯度計算兩點之間的距離 * create temporary function LocDistanceCalUDF as 'com.ai.hive.udf.util.LocDistanceCalUDF'; * @author olicity */ public class LocDistanceCalUDF extends UDF{ private static Logger log = Logger.getLogger(LocDistanceCalUDF.class); private Text nullText = new Text(""); /** *根據經緯度計算地球兩點間的距離 */ private static double distanceCal(double lng1, double lat1,double lng2,double lat2){ double dx = lng1 - lng2;// 經度差值 double dy= lat1 - lat2;// 緯度差值 double b = (lat1 + lat2) / 2.0;// 平均緯度 double Lx = Math.toRadians(dx)*6367000.0*Math.cos(Math.toRadians(b));// 東西距離 double Ly = 6367000.0*Math.toRadians(dy);// 南北距離 return Math.sqrt(Lx*Lx+Ly*Ly);// 用平面的矩形對角距離公式計算總距離(米) } /** *重寫evaluate方法 */ public Text evaluate(Text longitudeText1, Text latitudeText1,Text longitudeText2, Text latitudeText2){ try{ if(longitudeText1==null || latitudeText1==null || longitudeText2==null || latitudeText2==null){ return nullText; } if(StringUtil.isEmpty(longitudeText1.toString()) || StringUtil.isEmpty(latitudeText1.toString()) || StringUtil.isEmpty(longitudeText2.toString()) || StringUtil.isEmpty(latitudeText2.toString())){ return nullText; } double lng1 = Double.valueOf(longitudeText1.toString()); double lat1 = Double.valueOf(latitudeText1.toString()); double lng2 = Double.valueOf(longitudeText2.toString()); double lat2 = Double.valueOf(latitudeText2.toString()); double dis = distanceCal(lng1,lat1,lng2,lat2); return new Text(String.valueOf(dis)); }catch (Exception e){ return nullText; } } /** *重寫evaluate方法 */ public Text evaluate(Text locationA,Text locationB){ try{ if (locationA==null||locationB==null){ return nullText; } if(StringUtil.isEmpty(locationA.toString()) || StringUtil.isEmpty(locationB.toString())){ return nullText; } String locationA2String = locationA.toString(); String locationB2String = locationB.toString(); double lng1 = Double.valueOf(locationA2String.split(",")[0]); double lat1 = Double.valueOf(locationA2String.split(",")[1]); double lng2 = Double.valueOf(locationB2String.split(",")[0]); double lat2 = Double.valueOf(locationB2String.split(",")[1]); double dis = distanceCal(lng1,lat1,lng2,lat2); return new Text(String.valueOf(dis)); }catch(Exception e){ return nullText; } } }
UDF類要繼承org.apache.hadoop.hive.ql.exec.UDF類,類中要實現evaluate。 當我們在hive中使用自定義的UDF的時候,hive會呼叫類中的evaluate方法來實現特定的功能。
二、UDF匯入
1.jar包上傳
右鍵類名,Copy reference,複製此類全路徑得到:com.ai.hive.udf.util.LocDistanceCalUDF。將寫完的類打成jar包上傳到伺服器。路徑如:/user/olicity/hive/UDF
2.jar包引入classpath變數中
進入hive,引入jar包,執行命令
add jar /user/olicity/hive/UDF/udf.jar;
檢視匯入的jar包
list jars;
3.建立函式
建立一個名為LocDistanceCalUDF的臨時函式,關聯該jar包
create temporary function LocDistanceCalUDF as 'com.ai.hive.udf.util.LocDistanceCalUDF';
檢視建立的函式
show functions;
4.注意
上述方法僅限於當前會話生效,如需要新增一個永久的函式對應的永久的路徑,則
create function locUDF.LocDistanceCalUDF as 'com.ai.hive.udf.util.LocDistanceCalUDF' using jar 'hdfs://hdfs路徑/udf.jar'; use LocDistanceCalUDF;
需要將jar包放到hdfs上,然後建立函式關聯路徑即可。 另外還看到過另一種方法,配置hive-site.xml檔案中的hive.aux.jars.path
配置參考如下:
<property>
<name>hive.aux.jars.path</name>
<value>file:///home/hdfs/fangjs/DefTextInputFormat.jar,file:///jarpath/test.jar</value>
</property>
三、UDF使用
準備工作已經就緒,可以開始查表了。emmmmm,就簡單的倆表查吧,表結構和表資料就不展示了,示例表也就不建了,所給經緯度表叫A表,需要查詢的表叫B表,臨時中間表叫c表,經緯度的表中欄位定義是loc,距離就算2公里吧。
create table C
as
select B.* from B join A where (LocDistanceCalUDF(A.loc,B.loc)<=2000);
OK.
四、總結
關於sql語句還是需要再多加練習,尤其是多表聯查。Hadoop之路任重而道遠。