hive自定义UDTF

UDTF:一进多出
举例:自定义一个UDTF实现将一个任意分隔符的字符串切割成独立的单词,例如:
Line:“hello,world,hadoop,hive”
Myudtf(line, “,”)
hello
world
hadoop
hive
在这里插入图片描述

 

package hive.udtf;

import com.sun.corba.se.spi.ior.ObjectId;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class MyUDTF extends GenericUDTF{

    private List<String> dataList=new ArrayList<>();
    
    //定义输出数据的列名和数据类型

public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        
        //定义输出数据的列名
        List <String> structFieldNames=new ArrayList<>();
        structFieldNames.add("word");
        
        //定义输出数据的类型
        List<ObjectInspector> structFieldObjectInspectors=new ArrayList<>();
        structFieldObjectInspectors.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        
        return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, structFieldObjectInspectors);
    }
    
    @Override
    public void process(Object[] args) throws HiveException {
        
        //1.获取数据
        String data = args[0].toString();
        
        //2.获取分隔符
        String splitKey = args[1].toString();
        
        //3.切分数据
        String[] words = data.split(splitKey);
        
        //4.遍历写出
        for (String word : words) {
            
            //5.将数据放置集合
            dataList.clear();
            dataList.add(word);
            
            //6.写出数据的操作
            forward(dataList);
            
        }
                
    }

    @Override
    public void close() throws HiveException {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

eg2:

UDTF(User-Defined Table-Generating Functions)一进多出,如lateral view explore()

实现方法:

1)继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF

2)重写initialize、process、close方法

UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型,名称)。初始化完成后,会调用process方法,对传入的参数进行处理,可以通过forword()方法把结果返回。最后close()方法调用,对需要清理的方法进行清理

应用案例

需求:使用自定义UDTF函数获取两个时间之间的时间列表

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

package com.sjck.hive.udf;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.Calendar;

import java.util.Date;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;

import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;

import org.apache.hadoop.hive.ql.metadata.HiveException;

import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;

import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;

import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;

import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class DateMap extends GenericUDTF {

    @Override

    public void close() throws HiveException {

    }

     

    @Override

    public StructObjectInspector initialize(ObjectInspector[] args) throws UDFArgumentException {

        if (args.length != 2) {

            throw new UDFArgumentLengthException("DateMap takes only two argument");

        }

        ArrayList<String> fieldNames = new ArrayList<String>();

        ArrayList<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();

        fieldNames.add("begin_date"); //指定输出参数名称

        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        fieldNames.add("end_date");

        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);

        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);

    }

     

    @Override

    public void process(Object[] args) throws HiveException {

        try {

            String begin = String.valueOf(args[0]);

            String end = String.valueOf(args[1]);

            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

            int days = (int) (dateFormat.parse(end).getTime() - dateFormat.parse(begin).getTime())

                    / (60 60 24 1000);

            Date startDate = timeFormat.parse(begin);

            Date endDate = timeFormat.parse(end);

            Calendar ecalendar = Calendar.getInstance();

            ecalendar.setTime(startDate);

             

            Date d1 = startDate;

            Date d2 = null;

             

            if(days==0){

                d2=endDate;        

            }else{

                ecalendar.add(Calendar.DATE, 1);

                ecalendar.set(Calendar.HOUR_OF_DAY, 0);

                ecalendar.set(Calendar.MINUTE, 0);

                ecalendar.set(Calendar.SECOND, 0);

                d2=ecalendar.getTime();

             

            }

            String datas[][] = new String[days + 1][2];

            datas[0][0] = timeFormat.format(d1);

            datas[0][1] = timeFormat.format(d2);

            for (int i = 1; i < days + 1; i++) {

                d1 = d2;

                ecalendar.add(Calendar.DATE, 1);

                d2 = ecalendar.getTime();

                if (d2.after(endDate)) {

                    d2 = endDate;

                }

                datas[i][0] = timeFormat.format(d1);

                datas[i][1] = timeFormat.format(d2);

                 

            }

            for (int i = 0; i < datas.length; i++) {

                String[] s = new String[2];

                s[0] = datas[i][0];

                s[1] = datas[i][1];

                forward(s);

            }

        catch (ParseException e) {

            e.printStackTrace();

        }

    }

     

}

将代码打成jar包上传到服务器上,我这边是上传到hdfs上的

hadoop fs -put  hive-udf.jar /user/hive/udf

声明函数

create function datemap AS 'com.sjck.hive.udf.DateMap' using jar 'hdfs://nameservice1/user/hive/udf/hive-udf.jar';  

使用

方式一:直接放在select后面

看下使用到表结构

select  * from   bst_bas_driver_info_work_time where id='2440780' //看看选择的一条数据

 

 使用datemap函数获取开始时间-结束时间中间的时间(按天展开)

select datemap(date_format(t.work_start_time, 'yyyy-MM-dd HH:mm:ss'),date_format(t.work_end_time, 'yyyy-MM-dd HH:mm:ss')) as (begin_date,end_date) from bst_bas_driver_info_work_time t
where id='2440780'

注意:

1)不可以添加其他字段使用:
select datemap(date_format(t.work_start_time, 'yyyy-MM-dd HH:mm:ss'),date_format(t.work_end_time, 'yyyy-MM-dd HH:mm:ss')) as (begin_date,end_date)  from bst_bas_driver_info_work_time t where id='2440780'
2)不可以嵌套调用:
select datemap(datemap(xx,xxx),datemap(xx,xxx)) from bst_bas_driver_info_work_time
3)不可以和group by/cluster by/distribute by/sort by一起使用:
select datemap(xx,xxx)as (begin_date,end_date) from bst_bas_driver_info_work_time group by begin_date, end_date 

 方式二:和lateral view一起使用

1

2

3

4

5

6

7

select work_start_time  as start_date,

       work_end_time    as end_date,

       t.mid_start_date,

       t.mid_end_date

  from bst_bas_driver_info_work_time lateral view datemap(date_format(work_start_time, 'yyyy-MM-dd HH:mm:ss'), date_format(work_end_time, 'yyyy-MM-dd HH:mm:ss')) t as mid_start_date,

       mid_end_date

 where id in ('2440780') 

 其实这个功能用posexplode也可以完成,看下代码:

效果一样,只不过中间逻辑自己还得单独做处理下,代码参考我的另一篇Hive列出两个时间中的时间列表 - 楔子 - 博客园

这里重点在于UDTF自定义函数的实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值