目录
0.需求来源
1.创建maven项目
2.上传jar包到hdfs上
3.创建函数
4.使用函数
最近,接到这么一个需求,需要统计用户在一天中的各个时间段(比如02:00-09:00点)的电影播放时长,评估了一下需求,使用hiveql无法进行这种计算,因为我们的数据长这样:
数据是按天分区的,时长粒度也是为天的,要想分时段统计就必须要有小时分区的数据,况且它这个开始结束时间居然存在跨天的数据,本来不打算做的了,,可悲的是客户都是大爷,让你做啥你还不能拒绝,仔细分析了一下,这种逻辑运算使用hive肯定是搞不定的,上百万的数据又不可能使用java来处理,于是乎就想到了hive的udf函数,我们可以将一天的一条记录根据开始和结束时间拆分成多个小时批次,每个小时批次单独计算自己的时长,这样就能单独计算各个时间段内的播放时长了。
先放结果:select udf_interval_to_hourno('2019-11-11 20:15:12','2019-11-12 22:59:00');
这个结果是返回一个由每个小时分区和时长连接的字符串 2019111120-912,2019111121-3600,2019111122-3600,2019111123-3600,2019111220-3540,我们在hive中还需要对其进行一行转多列再分割处理,然后就可以进行汇总了。
这个函数的思想比较简单,对于开始时间和结束时间来说,我们只要关心开始结束的时间就好了,至于中间的跨小时的时长肯定是按小时划分的,即3600秒,确定好开始和结束时间的小时批次就行,开搞
首先,使用idea创建maven工程,然后pom.xml添加如下依赖,hive版本和hadoop版本请写自己平台的:
org.apache.hive
hive-exec
2.1.1
org.apache.hadoop
hadoop-common
2.6.5
UdfIntervalToHourBatch
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
1.8
类代码如下,普通的Udf函数直接继承UDF然后覆写evaluate函数即可:
public class UdfIntervalToHourBatch extends UDF {
public String evaluate(String begintime,String endtime){
if(null==begintime || null==endtime || begintime.length()!=19 || endtime.length()!=19){
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dBegin=null;
Date dEnd=null;
String beginBatchHour=begintime.substring(0,4)+begintime.substring(5,7)+begintime.substring(8,10)+begintime.substring(11,13);
String endBatchHour=endtime.substring(0,4)+endtime.substring(5,7)+endtime.substring(8,10)+endtime.substring(11,13);
//String beginBatchDay=begintime.substring(0,4)+begintime.substring(5,7)+begintime.substring(8,10);
//String endBatchDay=endtime.substring(0,4)+endtime.substring(5,7)+endtime.substring(8,10);
try{
dBegin = sdf.parse(begintime);
dEnd = sdf.parse(endtime);
}catch(Exception e){
e.printStackTrace();
}
if(dBegin.getTime()>dEnd.getTime()){
return null;
}
if(beginBatchHour.equals(endBatchHour)){
long diff=dEnd.getTime()-dBegin.getTime();
long seconds=diff/1000;
return beginBatchHour+"-"+seconds;
}else{
long beginSeconds=3600-(dBegin.getMinutes()*60+dBegin.getSeconds());
String beginBatch=beginBatchHour+"-"+beginSeconds;
List listDate = new ArrayList();
Calendar calBegin = Calendar.getInstance();
calBegin.setTime(dBegin);
Calendar calEnd = Calendar.getInstance();
calEnd.setTime(dEnd);
while (calEnd.after(calBegin)){
calBegin.add(Calendar.HOUR, 1);
if (calEnd.after(calBegin)){
listDate.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calBegin.getTime()));
}
}
long endSeconds=dEnd.getMinutes()*60+dEnd.getSeconds();
String endBatch=endBatchHour+"-"+endSeconds;
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append(beginBatch+",");
for (int i=0;i
直接使用maven打包->package,然后可以在hdfs上面自己建目录单独存放udf函数!
hdfs dfs -mkdir /udf
hdfs dfs -put /localpath/xx.jar /udf/
然后我们就可以使用自己的函数搞事情了,创建永久函数如下:
create function db.udf_interval_to_hourno as 'com.udf.UdfIntervalToHourBatch' using jar 'hdfs://SH1/udf/UdfIntervalToHourBatch.jar';
这里需要确认自己的主类位置以及hdfs上面的位置,至于数据库名db的话看个人咯,用不用都行,创建临时函数就多加一个关键字 temporary即可
第0点里面已经提到,略过
是不是很简单,懂一点java就可以使用udf做一些复杂的逻辑计算了!