Pig、Hive 解决分组 TopK 问题

本文参考链接:http://my.oschina.net/leejun2005/blog/85187

他的有关hadoop/pig/hive/hbase的其他文章:http://my.oschina.net/leejun2005/blog?catalog=186187

问题:

有如下数据文件 city.txt (id, city, value)

cat city.txt 
1 wh 500
2 bj 600
3 wh 100
4 sh 400
5 wh 200
6 bj 100
7 sh 200
8 bj 300
9 sh 900
需要按 city 分组聚合,然后从每组数据中取出前两条value最大的记录。

1、这是实际业务中经常会遇到的 group TopK 问题,下面来看看 pig 如何解决:

1a = load '/data/city.txt'  using PigStorage(' ') as (id:chararray, city:chararray, value:int);
2b = group a by city;
3c = foreach b {c1=order a by value desc; c2=limit c1 2; generate group,c2.value;};
4d = stream c through `sed 's/[(){}]//g'`;
5dump d;
结果:
1(bj,600,300)
2(sh,900,400)
3(wh,500,200)
这几行代码其实也实现了mysql中的 group_concat 函数的功能:
1a = load '/data/city.txt'  using PigStorage(' ') as (id:chararray, city:chararray, value:int);
2b = group a by city;
3c = foreach b {c1=order a by value desc;  generate group,c1.value;};
4d = stream c through `sed 's/[(){}]//g'`;
5dump d;
结果:
1(bj,600,300,100)
2(sh,900,400,200)
3(wh,500,200,100)

2、下面我们再来看看hive如何处理group topk的问题:

本质上HSQL和sql有很多相同的地方,但HSQL目前功能还有很多缺失,至少不如原生态的SQL功能强大,

比起PIG也有些差距,如果SQL中这类分组topk的问题如何解决呢?

1select * from city a where
22>(select count(1) from city where cname=a.cname and value>a.value)
3distribute by a.cname sort by a.cname,a.value desc;
http://my.oschina.net/leejun2005/blog/78904

但是这种写法在HQL中直接报语法错误了,下面我们只能用hive udf的思路来解决了:

排序city和value,然后对city计数,最后where过滤掉city列计数器大于k的行即可。

好了,上代码:

(1)定义UDF:

01package com.example.hive.udf;
02import org.apache.hadoop.hive.ql.exec.UDF;
03      
04public final class Rank extends UDF{
05    private int  counter;
06    private String last_key;
07    public int evaluate(final String key){
08      if ( !key.equalsIgnoreCase(this.last_key) ) {
09         this.counter = 0;
10         this.last_key = key;
11      }
12      return this.counter++;
13    }
14}
(2)注册jar、建表、导数据,查询:
1add jar Rank.jar;
2create temporary function rank as 'com.example.hive.udf.Rank';
3create table city(id int,cname string,value int) row format delimited fields terminated by ' ';
4LOAD DATA LOCAL INPATH 'city.txt' OVERWRITE INTO TABLE city;
5select cname, value from (
6    select cname,rank(cname) csum,value from (
7        select id, cname, value from city distribute by cname sort by cname,value desc
8    )a
9)b where csum < 2;

(3)结果:

1bj  600
2bj  300
3sh  900
4sh  400
5wh  500
6wh  200
可以看到,hive相比pig来说,处理起来稍微复杂了点,但随着hive的日渐完善,以后比pig更简洁也说不定。

REF:hive中分组取前N个值的实现

http://baiyunl.iteye.com/blog/1466343


PS:

如果说hive类似sql的话,那pig就类似plsql存储过程了:程序编写更自由,逻辑能处理的更强大了。

pig中还能直接通过反射调用java的静态类中的方法,这块内容请参考之前的相关pig博文。

附几个HIVE UDAF链接,有兴趣的同学自己看下:

Hive UDAF和UDTF实现group by后获取top值 http://blog.csdn.net/liuzhoulong/article/details/7789183
hive中自定义函数(UDAF)实现多行字符串拼接为一行 http://blog.sina.com.cn/s/blog_6ff05a2c0100tjw4.html
编写Hive UDAF http://www.fuzhijie.me/?p=118
Hive UDAF开发 http://richiehu.blog.51cto.com/2093113/386113



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值