前言
在之前的章节中,我们介绍了Hadoop中的序列化,即Writable
。虽然Hadoop自身提供了很多内置的Writable实现,可以满足大部分需求。但在有些场景下,我们需要根据自己的需求构造一个新的实现。有了定制的Writable类型,就可以完全控制二进制表示和排序顺序。此外,在对于数据字段较多的场景下,我们也会构建一个新的实现,来包装这些字段。
案例1
假设我们的数据格式如下。
1 | 1,zhangsan,18,13888888888,Beijing,2017-02-10 |
每行数据以逗号分隔,各个字段的含义为:ID、用户名、年龄、手机号、地区以及注册时间。
下面请编写MapReduce程序,找到所有Beijing和Shanghai地区的用户,并按照用户年龄升序。
从需求中,我们屡屡思路:
- 找到Beijing和Shanghai的用户比较简单,将每行数据按照逗号分隔,找到相应位置的字段就好
- 按照用户年龄排序该怎么弄?
在前面MapReduce的执行流程中我们以及介绍过了,Map任务在将数据输出后,会按照Key进行排序。Reduce端将各个Map任务的输出数据获取后,也会进行排序。那么关键点就在于Key上了,只要我们能控制Key的排序规则,就可以了。之前我们都是用的Text
对象作为Key,现在已经不能满足需求了,我们需要自定义Writable对象。
自定义UserWritable
对象。
1 | /** |
UserMapper
类。
1 | public class UserMapper extends Mapper<LongWritable, Text, UserWritable, NullWritable> { |
UserReducer
类。
1 | public class UserReducer extends Reducer<UserWritable, NullWritable, UserWritable, NullWritable> { |
UserRunner
启动类。
1 | public class UserRunner extends Configured implements Tool { |
为了方便起见,我们可以直接在本地运行调试。最终结果如下。
1 | 5,xiaomao,17,13312345678,Beijing,2017-02-10 |
案例2
对下列数据进行排序。
1 | a 5 |
要求,第一列按照字典顺序排序,如果第一列相同,第二列按照降序排列。例如,<a, 2>和<a, 5>,排序后应当<a, 5>在前,<a. 2>在后。
先屡屡思路:
- 要根据特殊的规则进行排序,需要定义排序规则,即要自定义Writable对象
- MapReduce自动根据Key排序,因此数据输出要将自定义对象作为Key,不需要Value,用NullWritable即可
首先是自定义对象。
1 | public class PairWritable implements WritableComparable<PairWritable> { |
PairMapper
类。
1 | public class PairMapper extends Mapper<LongWritable, Text, PairWritable, NullWritable> { |
PairReducer
类。
1 | public class PairReducer extends Reducer<PairWritable, NullWritable, PairWritable, NullWritable> { |
PairRunner
类。
1 | public class PairRunner extends Configured implements Tool { |
最终输出结果如下所示。
1 | a 5 |
小结
本章介绍了自定义Writable对象用法,如果要处理的数据字段有多个,或需要根据某种特定的规则进行排序,我们就需要构建自定义的Writable对象封装数据,并实现排序逻辑。此外,如果自定义对象作为Map任务的Key,则要实现WritableComparable接口,否则只需要实现Writable接口即可。本章中的两个案例有一定的代表性,希望大家能够自己完成。