欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hive开发UDF及使用

程序员文章站 2022-03-08 20:23:04
...

 最近有个数据挖掘的需求,要求统计所给经纬度附近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之路任重而道远。

相关标签: hadoop