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 |
|
将代码打成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 |
|
其实这个功能用posexplode也可以完成,看下代码:
效果一样,只不过中间逻辑自己还得单独做处理下,代码参考我的另一篇Hive列出两个时间中的时间列表 - 楔子 - 博客园
这里重点在于UDTF自定义函数的实现