Hive根据源码Example编写UDTF、UDF、UDAF函数

1,380 阅读2分钟

本篇博文,我将带你通过借助源码以及官方文档来完成自定义UDTF的编写与打包。当你阅读完本篇文章,你已经拥有了编写(UDF、UDAF)的能力,相信即使官方在新的版本上做出较大改动,你一样可以在短时间内驾驭它。

  • UDF(User-Defined-Function) 一进一出 eg:length(‘abcedfg’)
  • UDAF(User- Defined Aggregation Funcation) 聚合函数,多进一出 eg:COUNT/MAX
  • UDTF(User-Defined Table-Generating Functions) 一进多出 eg:split(‘abtcdtef’,'t’)

如何把写好的程序放入Hive,使方法中可调用

Hive自定义函数初步上手

Built-in Functions

UDTF Example

1、HiveWiki-UDTF介绍

cwiki.apache.org/confluence/…

2、ExampleCode

1)继承GenericUDTF方法

2)重写initialize方法。此方法返回UDTF的字段名信息(定义返回个数,类型)。

3)重写process方法。该方法就是用来处理你的业务逻辑的。

在process中,每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。

  1. 最后调用close方法。

借鉴源码中的例子编写UDTF。使用IDEA快捷键Ctrl+Shfit+N。随便点一个实现进去后就可以根据源码中的例子手写自己的UDF了。

3、输入地名,返回该地名的上下级关系。

    1         北京市
    2         山东省
    3         昌平区
    4         海淀区
    5         沙河镇
    6         马池口
    7         中关村
    8         上地
    9         烟台市
    10        青岛市
    11        牟平区
    12        芝罘区
    13        即墨区
    14        城阳

1)重写initialize()

	@Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
    	//定义返回列的列名
        List<String> colName = Lists.newLinkedList();
        colName.add("tag_province");
        colName.add("tag_city");
        colName.add("tag_area");
        
        //定义返回字段类型
        List<ObjectInspector> resType = new ArrayList<>();
        resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        resType.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        // 返回列名和列类型
        return ObjectInspectorFactory.getStandardStructObjectInspector(colName, resType);
    }

2)重写process()

	//定义一个数组,返回一行数据结果要使用数组装起来
	private Object[] forwardListObj = new Object[3];
	
    //执行业务代码
    @Override
    public void process(Object[] args) throws HiveException {

		//业务处理
        String area = existArea(args[0].toString());
        String city = existFather(area);
        String province = existFather(city);
		
        //结果装入定义好的数组
        forwardListObj[0] = province;
        forwardListObj[1] = city;
        forwardListObj[2] = area;

        //output
        forward(forwardListObj);

    }
    
   	//都写在process()不好看,拎出来。在process()中调用
   public String existArea(String value) {

        switch (value) {
            case "沙河镇":
            case "马池口镇":
            case "中关村":
            case "上地":
            case "牟平区":
            case "芝罘区":
            case "即墨区":
            case "城阳":
                return value;

            default:
                return "";
        }
    }
    public String existFather(String value) {

        switch (value) {
            case "昌平区":
            case "海淀区":
                return "北京市";
            case "沙河镇":
            case "马池口镇":
                return "昌平区";
            case "中关村":
            case "上地":
                return "海淀区";
            case "烟台市":
            case "青岛市":
                return "山东省";
            case "牟平区":
            case "芝罘区":
                return "烟台市";
            case "即墨区":
            case "城阳":
                return "青岛市";
            default:
                return value;
        }
    }

3)清理

@Override
    public void close() throws HiveException {
        //TODO........

    }

4)打包丢进Hive运行

丢之前最好先在本地开发机测试好,提高效率

hive> add jar /home/hadoop/app/xinxingdata-udf/lib/Xinxingdata-udf-1.0.jar;
Added [/home/hadoop/app/xinxingdata-udf/lib/Xinxingdata-udf-1.0.jar] to class path
Added resources: [/home/hadoop/app/xinxingdata-udf/lib/Xinxingdata-udf-1.0.jar]

hive> list jars;
/home/hadoop/app/xinxingdata-udf/lib/Xinxingdata-udf-1.0.jar

	//temporary 为临时函数,当前session结束后,jar包就会失效。
    //"xinxingdata.bigdata.UDF.AreaSplice"为你编写UDTF路径
hive> create temporary function geoSplit as "xinxingdata.bigdata.UDF.AreaSplice";
OK
Time taken: 0.346 seconds
//如果你想使UDF函数永久生效,请在 hive-site.xml 文件中添加:
<property>
<name>hive.aux.jars.path</name>
<value>file://[jar-localpath],[jar-localpath],[jar-localpath]</value>
</property>

创建永久生效的UDF
hive (default)>create  function geoSplit as "xinxingdata.bigdata.UDF.AreaSplice";

删除函数
hive (default)>drop function geoSplit;
注意:在哪个数据库中注册的永久函数,必须在哪个数据库下将该方法删除。

5)查询测试

select tag_province,tag_city,tag_area 
from (select  geoSplit(name) from address) a
where tag_province !="";

OK
tag_province	tag_city	tag_area
北京市	昌平区	沙河镇
北京市	昌平区	马池口镇
北京市	海淀区	中关村
北京市	海淀区	上地
山东省	烟台市	牟平区
山东省	烟台市	芝罘区
山东省	青岛市	即墨区
山东省	青岛市	城阳
Time taken: 0.039 seconds, Fetched: 8 row(s)