Hive自定义UDF-RowNumber

22 篇文章 0 订阅
12 篇文章 0 订阅

1. hive0.10及之前的版本没有row_number这个函数,假设我们现在出现如下业务场景,现在我们在hdfs上有个log日志文件,为了方便叙述,该文件只有2个字段,第一个是用户的id,第二个是当天登录的timestamp,现在我们需要求每个用户最早登录的那条记录(注意不是仅仅只要那个登录的timestamp),可以方便计算NewUser。

2. 我们的数据是这样的:

1,32
2,46
3,312
4,4643
5,54
6,456
7,437
8,5347
9,47
1,466
2,546
3,4
4,886
5,546
6,57
7,235
8,765
9,634
这里是假设的数据。

3.我们可以用hive建立一张表,其中第一个字段是id string, 第二个是login_time bigint,假设我们的表名是log。

4. 这样的场景可以用很多方法解决,但是我们可以用RowNumber函数,在0.11及以上的版本才集成到了hive中,但是我们公司用的是CDH4.5.0,hive才到0.10,所以只能自己写个这样的函数,具体的代码如下:

<span style="font-family:SimSun;font-size:14px;">import org.apache.hadoop.hive.ql.exec.UDF;

public class RowN extends UDF {

	private static int MAX_VALUE = 50;
	private static String comparedColumn[] = new String[MAX_VALUE];
	private static int rowNum = 1;

	public int evaluate(Object... args) {
		String columnValue[] = new String[args.length];
		for (int i = 0; i < args.length; i++) {
			columnValue[i] = args[i].toString();
		}
		if (rowNum == 1) {
			for (int i = 0; i < columnValue.length; i++)
				comparedColumn[i] = columnValue[i];
		}

		for (int i = 0; i < columnValue.length; i++) {
			if (!comparedColumn[i].equals(columnValue[i])) {
				for (int j = 0; j < columnValue.length; j++) {
					comparedColumn[j] = columnValue[j];
				}
				rowNum = 1;
				return rowNum++;
			}
		}
		return rowNum++;
	}
}
</span>

5. 稍微解释下这个UDF,首先我们的UDF函数输入是多个列的值,传入多个值表示用多个值是否相同来打序号,对于我们的场景只要1个(就是id),函数row_number(),必须带一个或者多个列参数,如ROW_NUMBER(col1, ....),它的作用是按指定的列进行分组生成行序列。在ROW_NUMBER(a,b) 时,若两条记录的a,b列相同,则行序列+1,否则重新计数。

6. 接下去关键的就是怎么取使用这个函数了,我们必须保证查出来的数据是有序的,这样才好加序号,而且要根据某个字段排序,但是如果数据量大或者我们自己设置了多个reducer咋办,这样的话我们就想到了使用distribute by和sort by的配合使用,可以使key相同的数据进入同一个reducer,这样就好办了,那么我们的hql语句其实就是一句话:

create temporary function RowNumber as 'xxx.xxx.xxx.udf.RowNumber';
select id, login_time from (select * from log distribute by id sort by id, login_time asc) tmp where RowNumber(id)=1;
结果为:

1 32
2 46
3 4
4 886
5 54
6 25
7 75
8 534
9 47

注:

1. 如果对distribute by不熟悉可以看另一个我的博客,有具体的解释:http://blog.csdn.net/jthink_/article/details/38903775

2. 这个函数最关键的部分就是得先有序,所以加序号前必须保证数据有序



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值