hive中使用自定义函数(UDF)实现分析函数row_number的功能

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,所以只能自己写个这样的函数,具体的代码如下:

[java]  view plain  copy
  1. import org.apache.hadoop.hive.ql.exec.UDF;  
  2.   
  3. public class RowN extends UDF {  
  4.   
  5.     private static int MAX_VALUE = 50;  
  6.     private static String comparedColumn[] = new String[MAX_VALUE];  
  7.     private static int rowNum = 1;  
  8.   
  9.     public int evaluate(Object... args) {  
  10.         String columnValue[] = new String[args.length];  
  11.         for (int i = 0; i < args.length; i++) {  
  12.             columnValue[i] = args[i].toString();  
  13.         }  
  14.         if (rowNum == 1) {  
  15.             for (int i = 0; i < columnValue.length; i++)  
  16.                 comparedColumn[i] = columnValue[i];  
  17.         }  
  18.   
  19.         for (int i = 0; i < columnValue.length; i++) {  
  20.             if (!comparedColumn[i].equals(columnValue[i])) {  
  21.                 for (int j = 0; j < columnValue.length; j++) {  
  22.                     comparedColumn[j] = columnValue[j];  
  23.                 }  
  24.                 rowNum = 1;  
  25.                 return rowNum++;  
  26.             }  
  27.         }  
  28.         return rowNum++;  
  29.     }  
  30. }  
  31.   

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语句其实就是一句话:

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

132
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. 这个函数最关键的部分就是得先有序,所以加序号前必须保证数据有序


你可能感兴趣的:(Hive)