Hadoop二次排序
2012-12-30 17:24
337 查看
转载自:http://www.fuzhijie.me/?p=34
我想涉及到文件的Join操作应该都要使用到二次排序吧,之前我用字符串拼接的方法显得太不专业了,本来在reduce过程中是不需要保存这些数据的,遍历一次便可以将记录全部collect好。Hadoop 0.20包里面有一个SecondarySort的例子程序,结合公司牛人写的一个ppt,终于搞明白了。呵呵,刚好也用上了,所以总结一下。
Hadoop提供了几种默认类型如果Text,LongWritable等,它们都实现了WritableComparable接口,因此具有比较和序列化的能力。要实现二次排序,我想大概有两种办法。第一种是使用自定义类型,该类型实现WritableComparable接口,给原始数据添加一个权值,通过权值来改变排序的结果;第二种方法是给记录的key做一些不同的标记,比如有些在最前面加上一个’+'前缀,另一些前面加上’-'前缀,通过这些前缀来决定排序的规则。这两种办法都要实现自己的分区函数和分组函数,因为key已经被改变了,显然第一种方法感觉要专业一点,但是第二种方法感觉要高效一些,因为不需要类来封装。
我使用了第一种方法来实现二次排序,需求是做一个一对多的文件连接。来一个形象的比喻,比如一个人去商场买东西,他推着购物车,每个商品都有自己唯一的编号。因此数据有两部分组成:
1、用户对商品编号,这是一对多的。数据保存在base.dat文件中。
2、商品编号对商品的信息,其中包括商品的价格,这是一对一的。数据保存在spu.dat文件中。
最后要生成用户对应商品价格记录,这样就可以统计出用户购买商品的总价格。这两个文件通过商品的编号连接。
程序很简单,自己定义了一个UserKey类,在这个类封装了原始数据,另外添加一个权重属性,排序时需要将商品对商品价格排到最前面去。注意这个compareTo方法返回值的涵义,返回-1表示自己要排在比较的记录之前,返回1表示自己要排在比较的记录之前,之前我一直以为返回1表示大于的意思,结果程序就出现了奇怪的现象。Hadoop没有使用Java默认的序列化方式,用户必须负责自定义类型的序列化接口的实现,我感觉下面的程序写得不够专业,这是我比较惯用的序列化手段,如果使用SequenceFileOutputFormat保存输出结果,可以看到对象序列化后的数据的保存方式,不过Java虚拟机统一了数据格式,因此不能使用C/C++的思维来观察这些数据,但是也差不多了。
全部源代码如下:
?
数据文件内容如下。
?
Job运行过程及生成数据结果如下所示:
?
Hadoop二次排序的理解。mapper生成的数据已经经过排序了,这些数据经过shuffle送到reducer。在交给reduce函数之前,记录需要经过排序和group。排序可以通过setOutputKeyComparatorClass进行干预,上面的例子程序中没有编写这个排序的类,它会使用Key的compareTo来排序。group通过setOutputValueGroupingComparator进行设置,它们的例子程序将商品编号相同的记录group到一起。
可以想象经过排序的结果如下:
?
group的结果如下:
?
我想涉及到文件的Join操作应该都要使用到二次排序吧,之前我用字符串拼接的方法显得太不专业了,本来在reduce过程中是不需要保存这些数据的,遍历一次便可以将记录全部collect好。Hadoop 0.20包里面有一个SecondarySort的例子程序,结合公司牛人写的一个ppt,终于搞明白了。呵呵,刚好也用上了,所以总结一下。
Hadoop提供了几种默认类型如果Text,LongWritable等,它们都实现了WritableComparable接口,因此具有比较和序列化的能力。要实现二次排序,我想大概有两种办法。第一种是使用自定义类型,该类型实现WritableComparable接口,给原始数据添加一个权值,通过权值来改变排序的结果;第二种方法是给记录的key做一些不同的标记,比如有些在最前面加上一个’+'前缀,另一些前面加上’-'前缀,通过这些前缀来决定排序的规则。这两种办法都要实现自己的分区函数和分组函数,因为key已经被改变了,显然第一种方法感觉要专业一点,但是第二种方法感觉要高效一些,因为不需要类来封装。
我使用了第一种方法来实现二次排序,需求是做一个一对多的文件连接。来一个形象的比喻,比如一个人去商场买东西,他推着购物车,每个商品都有自己唯一的编号。因此数据有两部分组成:
1、用户对商品编号,这是一对多的。数据保存在base.dat文件中。
2、商品编号对商品的信息,其中包括商品的价格,这是一对一的。数据保存在spu.dat文件中。
最后要生成用户对应商品价格记录,这样就可以统计出用户购买商品的总价格。这两个文件通过商品的编号连接。
程序很简单,自己定义了一个UserKey类,在这个类封装了原始数据,另外添加一个权重属性,排序时需要将商品对商品价格排到最前面去。注意这个compareTo方法返回值的涵义,返回-1表示自己要排在比较的记录之前,返回1表示自己要排在比较的记录之前,之前我一直以为返回1表示大于的意思,结果程序就出现了奇怪的现象。Hadoop没有使用Java默认的序列化方式,用户必须负责自定义类型的序列化接口的实现,我感觉下面的程序写得不够专业,这是我比较惯用的序列化手段,如果使用SequenceFileOutputFormat保存输出结果,可以看到对象序列化后的数据的保存方式,不过Java虚拟机统一了数据格式,因此不能使用C/C++的思维来观察这些数据,但是也差不多了。
全部源代码如下:
?
?
?
可以想象经过排序的结果如下:
?
?
相关文章推荐
- hadoop二次排序
- hadoop之二次排序
- hadoop二次排序
- Hadoop二次排序及MapReduce处理流程实例详解
- hadoop二次排序<转>
- Hadoop streaming 编写MapReduce程序-二次排序,多文件输入
- Hadoop学习笔记: MapReduce二次排序
- hadoop 二次排序
- hadoop 二次排序
- hadoop二次排序
- 【hadoop二次排序】Partitioner, SortComparator and GroupingComparator
- 02Hadoop二次排序2
- hadoop二次排序
- Hadoop MapReduce 深入理解!二次排序案例!
- Hadoop Mapreduce分区、分组、二次排序过程详解
- Hadoop MapReduce 二次排序原理及其应用
- MapReduce/Hadoop的二次排序解决方案
- Hadoop 二次排序 Secondary Sort
- 二次排序问题(分别使用Hadoop和Spark实现)
- python 实现Hadoop的partitioner和二次排序