问题:
有如下数据文件 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 如何解决:
1 |
a = load '/data/city.txt' using PigStorage( ' ' ) as (id:chararray, city:chararray, value: int ); |
3 |
c = foreach b {c1= order a by value desc ; c2=limit c1 2; generate group ,c2.value;}; |
4 |
d = stream c through `sed 's/[(){}]//g' `; |
结果:
这几行代码其实也实现了mysql中的 group_concat 函数的功能:
1 |
a = load '/data/city.txt' using PigStorage( ' ' ) as (id:chararray, city:chararray, value: int ); |
3 |
c = foreach b {c1= order a by value desc ; generate group ,c1.value;}; |
4 |
d = stream c through `sed 's/[(){}]//g' `; |
结果:
2、下面我们再来看看hive如何处理group topk的问题:
本质上HSQL和sql有很多相同的地方,但HSQL目前功能还有很多缺失,至少不如原生态的SQL功能强大,
比起PIG也有些差距,如果SQL中这类分组topk的问题如何解决呢?
但是这种写法在HQL中直接报语法错误了,下面我们只能用hive udf的思路来解决了:
排序city和value,然后对city计数,最后where过滤掉city列计数器大于k的行即可。
好了,上代码:
(1)定义UDF:
01 |
package com.example.hive.udf; |
02 |
import org.apache.hadoop.hive.ql. exec .UDF; |
04 |
public final class Rank extends UDF{ |
06 |
private String last_key; |
07 |
public int evaluate(final String key ){ |
08 |
if ( ! key .equalsIgnoreCase(this.last_key) ) { |
12 |
return this.counter++; |
(2)注册jar、建表、导数据,查询:
2 |
create temporary function rank as 'com.example.hive.udf.Rank' ; |
3 |
create table city(id int ,cname string,value int ) row format delimited fields terminated by ' ' ; |
4 |
LOAD DATA LOCAL INPATH 'city.txt' OVERWRITE INTO TABLE city; |
5 |
select 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 |
(3)结果:
可以看到,hive相比pig来说,处理起来稍微复杂了点,但随着hive的日渐完善,以后比pig更简洁也说不定。
REF:hive中分组取前N个值的实现
http://baiyunl.iteye.com/blog/1466343
3、最后我们来看一下原生态的MR:
01 |
import java.io.IOException; |
02 |
import java.util.TreeSet; |
04 |
import org.apache.hadoop.conf.Configuration; |
05 |
import org.apache.hadoop.fs.Path; |
06 |
import org.apache.hadoop.io.IntWritable; |
07 |
import org.apache.hadoop.io.LongWritable; |
08 |
import org.apache.hadoop.io.Text; |
09 |
import org.apache.hadoop.mapreduce.Job; |
10 |
import org.apache.hadoop.mapreduce.Mapper; |
11 |
import org.apache.hadoop.mapreduce.Reducer; |
12 |
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; |
13 |
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; |
14 |
import org.apache.hadoop.util.GenericOptionsParser; |
16 |
public class GroupTopK { |
17 |
// 这个 MR 将会取得每组年龄中 id 最大的前 3 个 |
18 |
// 测试数据由脚本生成:http://my.oschina.net/leejun2005/blog/76631 |
19 |
public static class GroupTopKMapper extends |
20 |
Mapper<LongWritable, Text, IntWritable, LongWritable> { |
21 |
IntWritable outKey = new IntWritable(); |
22 |
LongWritable outValue = new LongWritable(); |
23 |
String[] valArr = null ; |
25 |
public void map(LongWritable key, Text value, Context context) |
26 |
throws IOException, InterruptedException { |
27 |
valArr = value.toString().split( "\t" ); |
28 |
outKey.set(Integer.parseInt(valArr[ 2 ])); // age int |
29 |
outValue.set(Long.parseLong(valArr[ 0 ])); // id long |
30 |
context.write(outKey, outValue); |
34 |
public static class GroupTopKReducer extends |
35 |
Reducer<IntWritable, LongWritable, IntWritable, LongWritable> { |
37 |
LongWritable outValue = new LongWritable(); |
39 |
public void reduce(IntWritable key, Iterable<LongWritable> values, |
40 |
Context context) throws IOException, InterruptedException { |
41 |
TreeSet<Long> idTreeSet = new TreeSet<Long>(); |
42 |
for (LongWritable val : values) { |
43 |
idTreeSet.add(val.get()); |
44 |
if (idTreeSet.size() > 3 ) { |
45 |
idTreeSet.remove(idTreeSet.first()); |
48 |
for (Long id : idTreeSet) { |
50 |
context.write(key, outValue); |
55 |
public static void main(String[] args) throws Exception { |
56 |
Configuration conf = new Configuration(); |
57 |
String[] otherArgs = new GenericOptionsParser(conf, args) |
60 |
System.out.println(otherArgs.length); |
61 |
System.out.println(otherArgs[ 0 ]); |
62 |
System.out.println(otherArgs[ 1 ]); |
64 |
if (otherArgs.length != 3 ) { |
65 |
System.err.println( "Usage: GroupTopK <in> <out>" ); |
68 |
Job job = new Job(conf, "GroupTopK" ); |
69 |
job.setJarByClass(GroupTopK. class ); |
70 |
job.setMapperClass(GroupTopKMapper. class ); |
71 |
job.setReducerClass(GroupTopKReducer. class ); |
72 |
job.setNumReduceTasks( 1 ); |
73 |
job.setOutputKeyClass(IntWritable. class ); |
74 |
job.setOutputValueClass(LongWritable. class ); |
75 |
FileInputFormat.addInputPath(job, new Path(otherArgs[ 1 ])); |
76 |
FileOutputFormat.setOutputPath(job, new Path(otherArgs[ 2 ])); |
77 |
System.exit(job.waitForCompletion( true ) ? 0 : 1 ); |
hadoop jar GroupTopK.jar GroupTopK /tmp/decli/record_new.txt /tmp/1
结果:
hadoop fs -cat /tmp/1/part-r-00000
0 12869695
0 12869971
0 12869976
1 12869813
1 12869870
1 12869951
......
数据验证:
awk '$3==0{print $1}' record_new.txt|sort -nr|head -3
12869976
12869971
12869695
可以看到结果没有问题。
注:测试数据由以下脚本生成:
http://my.oschina.net/leejun2005/blog/76631
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
- 如何解决海量数据的Top K问题
1. 问题描述 在大规模数据处理中,常遇到的一类问题是,在海量数据中找出出现频率最高的前K个数,或者从海量数据中找出最大的前K个数,这类问题通常称为“top K”问题,如:在搜索引擎中,统计搜索最热门 ...
- 优先队列实现 大小根堆 解决top k 问题
摘于:http://my.oschina.net/leejun2005/blog/135085 目录:[ - ] 1.认识 PriorityQueue 2.应用:求 Top K 大/小 的元素 3 ...
- get top k elements of the same key in hive
key points: 1. group by key and sort by using distribute by and sort by. 2. get top k elements by a ...
- pig询问top k,每个返回hour和ad_network_id最大的两个记录(SUBSTRING,order,COUNT_STAR,limit)
pig里面有一个TOP功能.我不知道为什么用不了.有时间去看看pig源代码. SET job.name 'top_k'; SET job.priority HIGH; --REGISTER piggy ...
- Top K问题的两种解决思路
Top K问题在数据分析中非常普遍的一个问题(在面试中也经常被问到),比如: 从20亿个数字的文本中,找出最大的前100个. 解决Top K问题有两种思路, 最直观:小顶堆(大顶堆 -> 最小1 ...
- pig中查询top k,返回每个hour和ad_network_id下最大两个记录(SUBSTRING,order,COUNT_STAR,limit)
pig里面是有TOP函数,不知道为什么用不了.有时间要去看看pig源码了. SET job.name 'top_k'; SET job.priority HIGH; --REGISTER piggyb ...
- 优先队列PriorityQueue实现 大小根堆 解决top k 问题
转载:https://www.cnblogs.com/lifegoesonitself/p/3391741.html PriorityQueue是从JDK1.5开始提供的新的数据结构接口,它是一种基于 ...
- 海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)
前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些. 先拿10000个数建堆, ...
- pig hive 区别
Pig是一种编程语言,它简化了Hadoop常见的工作任务.Pig可加载数据.表达转换数据以及存储最终结果.Pig内置的操作使得半结构化数据变得有意义(如日志文件).同时Pig可扩展使用Java中添加的 ...
- linux命令之高级使用 find
1. 想查看当前文件夹及子文件夹里有没有文件名为“abc”的文件 # find . -name abc . :表示当前目录 -name:表示要根据名称查找 2. 想查看当前文件夹及子文件夹里有没有”x ...
- mysql中文排序问题
mysql中文排序,用到的是: SELECT id id, billId billId, namespec nameSpec, unit unit, amount amount, price pric ...
- 恶习为什么难戒?因为你在HALT状态
幸福课 | 恶习为什么难戒?因为你在HALT状态 文 游识猷 饥饿(hungry).生气(angry).孤单(lonely).疲惫(tired)这4种状态,被称为HALT——这个词刚好是英 ...
- SPI_FLASH时序描述及驱动编程
推荐 分享一个朋友的人工智能教程,零基础!通俗易懂!希望你也加入到人工智能的队伍中来! http://www.captainbed.net/strongerhuang Ⅰ.写在前面 前面文章讲述过关于 ...
- Android开发 - 图形化生成的贝塞尔插值器
基于三次方贝塞尔曲线的插值器 在动画开发过程中,经常需要使用到插值器来满足我们的动画设计需求.然而,官方提供的插值器并不能满足所有的需求,所以我们需要自定义插值器. 下面介绍的三次方贝塞尔曲线的插值器 ...
- Check the difficulty of problems - poj 2151 (概率+DP)
有 T(1<T<=1000) 支队伍和 M(0<M<=30) 个题目,已知每支队伍 i 解决每道题目 j 的的概率 p[i][j],现在问:每支队伍至少解决一道题,且解题最多的 ...
- windows下GVIM的配置(vimrc)
学习python时想要在gvim中配置python的编译环境,网上找到一个比较好用的vimrc配置,保存下来以备下次有需要. set encoding=utf-8 set termencoding=u ...
- C++ STL标准模板库(stack)
//stack的使用 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<stack> using name ...
- 首次接触XAMPP,端口被占用困恼
本人运气比较好,首次安装XAMPP就碰到了各种问题啊!并且已经解决,以下是我问题的出处并且解决. 问题描述: apache无法打开,并且连带的出现了mySql无法打开.(即80端口冲突问题) 解决办法 ...
- 图像jpeg压缩
图像分割 8X8 颜色空间转换RGB->YCbCr 3个8X8的矩阵 离散余弦变换:(Discrete cosine transform),简称DCT. DCT转换后的数组中第一个是一个直线数据 ...