MapReduce编程总结
mapreduce
在编程的时候,基本上一个固化的模式,没有太多可灵活改变的地方,除了以下几处:
-
输入数据接口:
InputFormat
—>FileInputFormat
(文件类型数据读取的通用抽象类)DBInputFormat
(数据库数据读取的通用抽象类)
默认使用的实现类是:TextInputFormat
job.setInputFormatClass(TextInputFormat.class)
TextInputFormat
的功能逻辑是:一次读一行文本,然后将该行的起始偏移量作为key
,行内容作为value
返回 -
逻辑处理接口:
Mapper
完全需要用户自己去实现其中map() setup() clean()
-
map
输出的结果在shuffle
阶段会被partition
以及sort
,此处有两个接口可自定义:Partitioner
,默认实现HashPartitioner
,逻辑是 根据key
和numReduces
来返回一个分区号;key.hashCode()&Integer.MAXVALUE % numReduces
通常情况下,用默认的这个
HashPartitioner
就可以,如果业务上有特别的需求,可以自定义Comparable
,当我们用自定义的对象作为key
来输出时,就必须要实现WritableComparable
接口,override
其中的compareTo()
方法 -
reduce
端的数据分组比较接口 :Groupingcomparator
reduceTask
拿到输入数据(一个partition
的所有数据)后,首先需要对数据进行分组,其分组的默认原则是key
相同,然后对每一组kv
数据调用一次reduce()
方法,并且将这一组kv
中的第一个kv
的key
作为参数传给reduce
的key
,将这一组数据的value
的迭代器传给reduce()
的values
参数利用上述这个机制,我们可以实现一个高效的分组取最大值的逻辑:
自定义一个bean
对象用来封装我们的数据,然后改写其compareTo
方法产生倒序排序的效果
然后自定义一个Groupingcomparator
,将bean
对象的分组逻辑改成按照我们的业务分组id
来分组(比如订单号)
这样,我们要取的最大值就是reduce()
方法中传进来key
-
逻辑处理接口:
Reducer
完全需要用户自己去实现其中reduce() setup() clean()
-
输出数据接口:
OutputFormat
—> 有一系列子类FileOutputformat
DBoutputFormat
…
默认实现类是TextOutputFormat
,功能逻辑是: 将每一个KV
对向目标文本文件中输出为一行