MapReduce 编程 系列二 编写简单mapper
2014-09-25 23:44
176 查看
MapReduce的基本流程是, 框架会使用FileInputFormat读取文件,默认会根据文件大小的进行记录拆分,这里拆分器叫做InputSplitter。通过InputSplitter将文件拆成若干块,后面也就有若干个mapper与之对应。
InputSplitter里面使用RecordReader对文件块的记录进行读取,生成key/value的pair,调用mapper的map函数去处理。
当然这些流程中有些可以定制,比如InputSplitter的算法可以修改,RecordReader也是可以定制。
而且还有一个非常有效的方法,可以避免mapper将过多的数据传递给reducer。
比如前面的例子都是1, 其实可以先用一个HashMap对key做分组,有则value加1, 无则添加到HashMap中。
最后将分组统计后的key/value数据通过context.write方法发送给reducer,能够大大提高效率。
现在想从日志中提取数据,日志文件如下:
2014-05-10 13:36:40,140307000287,536dbacc4700aab274729cca,login
2014-05-10 13:37:46,140310000378,536dbae74700aab274729ccb,login
2014-05-10 13:39:20,140310000382,536dbb284700aab274729ccd,login
2014-05-10 13:39:31,140331001080,536dbb864700aab274729ccf,login
2014-05-10 13:39:45,140331001105,536dbba04700aab274729cd4,login
2014-05-10 13:39:45,140328000969,536dbba04700aab274729ce4,login
2014-05-10 13:39:45,140408001251,536dbba04700aab274729cd8,login
2014-05-10 13:39:45,140328000991,536dbba04700aab274729ce9,login
2014-05-10 13:39:45,140324000633,536dbba14700aab274729cf5,login
2014-05-10 13:39:45,140331001077,536dbba04700aab274729cdd,login
2014-05-10 13:39:45,140408001242,536dbba04700aab274729cd7,login
2014-05-10 13:39:45,140327000941,536dbba14700aab274729cf1,login
2014-05-10 13:39:45,140408001265,536dbba04700aab274729ce5,login
2014-05-10 13:39:45,140324000673,536dbba04700aab274729cd3,login
2014-05-10 13:39:45,140331001066,536dbba04700aab274729cd5,login
2014-05-10 13:39:45,140408001292,536dbba14700aab274729cee,login
2014-05-10 13:39:45,140328000966,536dbba14700aab274729cec,login
2014-05-10 13:39:45,140312000501,536dbba04700aab274729ce1,login
2014-05-10 13:39:45,140306000216,536dbba14700aab274729d02,login
2014-05-10 13:39:45,140327000856,536dbba04700aab274729ce2,login
2014-05-10 13:39:46,140328000985,536dbba14700aab274729cf7,login
2014-05-10 13:39:46,140306000245,536dbba14700aab274729d0d,login
2014-05-10 13:39:46,140326000797,536dbba14700aab274729cf6,login
2014-05-10 13:39:46,140328000993,536dbba14700aab274729d12,login
2014-05-10 13:39:46,140331001115,536dbba14700aab274729d10,login
2014-05-10 13:39:46,140325000744,536dbba04700aab274729ce0,login
2014-05-10 13:39:46,140328000982,536dbba14700aab274729d0a,login
2014-05-10 13:39:46,140331001063,536dbba04700aab274729ce3,login
2014-05-10 13:39:46,140331001067,536dbba14700aab274729d1c,login
2014-05-10 13:39:46,140401001157,536dbba04700aab274729ce8,login
2014-05-10 13:39:46,140408001216,536dbba14700aab274729cef,login
2014-05-10 13:39:46,140401001174,536dbba14700aab274729d27,login
2014-05-10 13:39:46,140306000215,536dbba04700aab274729cde,login
2014-05-10 13:39:46,140331001064,536dbba04700aab274729cdc,login
2014-05-10 13:39:46,140326000825,536dbba04700aab274729cd9,login
2014-05-10 13:39:46,140408001294,536dbba14700aab274729d0f,login
我希望将login前面的设备ID取出来,进行数量的统计,最后得到结果:
各个设备的累计登录次数
536dbba04700aab274729cdc 5
536dbba04700aab274729ce3 4
好,创建一个LogMapper类,该类负责做数据的Map,前两各模板参数用于KeyIn和ValueIn, 后两个模板参数用于KeyOut和ValueOut,都是代表类型。
假定一个<KeyIn, ValueIn>组成一个pair,输入的很多pair在一个组里面, 这些pair被一定的算法Map之后,会变成很多组pair。
官方文档:http://hadoop.apache.org/docs/r2.4.1/api/org/apache/hadoop/mapreduce/Mapper.html
Maps input key/value pairs to a set of intermediate key/value pairs.注意,这里的Mapper类用的包是mapreduce,以前有一个老的叫mapred。
这里介绍了两者的区别:
http://stackoverflow.com/questions/7598422/is-it-better-to-use-the-mapred-or-the-mapreduce-package-to-create-a-hadoop-job
LongWritable和IntWritable是两个类,用于帮助创建可以Long和Int类型的变量。它们能够帮助将Long和Int的值序列化成字节流,因此都有两个关键方法读入和写出:
这个和Hadoop内部RPC调用时采用的序列化算法有关。
我的Mapper代码:
package org.freebird.mapper;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class LogMapper
extends Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable ONE = new IntWritable(1);
public void map(Object key, Text value, org.apache.hadoop.mapreduce.Mapper.Context context) throws IOException, InterruptedException {
String[] line = value.toString().split(",");
if (line.length == 4) {
String dId = line[2];
context.write(new Text(dId), ONE);
}
}
}
这个Mapper的子类覆盖了map函数,将字符串用,号拆开后,取出第三个元素作为设备ID, 然后作为key写入context对象。这里value设置为1, 因为后面reduce阶段会简单的求和。
Context类文档参考: http://hadoop.apache.org/docs/r1.1.1/api/org/apache/hadoop/mapreduce/Mapper.Context.html
write方法不是一般概念的hasmap添加key,value,而是生成一个新的pair对象,里面包含了key和value。 如果多个key相同,也会产生多个pair对象,交给reduce阶段处理。
InputSplitter里面使用RecordReader对文件块的记录进行读取,生成key/value的pair,调用mapper的map函数去处理。
当然这些流程中有些可以定制,比如InputSplitter的算法可以修改,RecordReader也是可以定制。
而且还有一个非常有效的方法,可以避免mapper将过多的数据传递给reducer。
比如前面的例子都是1, 其实可以先用一个HashMap对key做分组,有则value加1, 无则添加到HashMap中。
最后将分组统计后的key/value数据通过context.write方法发送给reducer,能够大大提高效率。
现在想从日志中提取数据,日志文件如下:
2014-05-10 13:36:40,140307000287,536dbacc4700aab274729cca,login
2014-05-10 13:37:46,140310000378,536dbae74700aab274729ccb,login
2014-05-10 13:39:20,140310000382,536dbb284700aab274729ccd,login
2014-05-10 13:39:31,140331001080,536dbb864700aab274729ccf,login
2014-05-10 13:39:45,140331001105,536dbba04700aab274729cd4,login
2014-05-10 13:39:45,140328000969,536dbba04700aab274729ce4,login
2014-05-10 13:39:45,140408001251,536dbba04700aab274729cd8,login
2014-05-10 13:39:45,140328000991,536dbba04700aab274729ce9,login
2014-05-10 13:39:45,140324000633,536dbba14700aab274729cf5,login
2014-05-10 13:39:45,140331001077,536dbba04700aab274729cdd,login
2014-05-10 13:39:45,140408001242,536dbba04700aab274729cd7,login
2014-05-10 13:39:45,140327000941,536dbba14700aab274729cf1,login
2014-05-10 13:39:45,140408001265,536dbba04700aab274729ce5,login
2014-05-10 13:39:45,140324000673,536dbba04700aab274729cd3,login
2014-05-10 13:39:45,140331001066,536dbba04700aab274729cd5,login
2014-05-10 13:39:45,140408001292,536dbba14700aab274729cee,login
2014-05-10 13:39:45,140328000966,536dbba14700aab274729cec,login
2014-05-10 13:39:45,140312000501,536dbba04700aab274729ce1,login
2014-05-10 13:39:45,140306000216,536dbba14700aab274729d02,login
2014-05-10 13:39:45,140327000856,536dbba04700aab274729ce2,login
2014-05-10 13:39:46,140328000985,536dbba14700aab274729cf7,login
2014-05-10 13:39:46,140306000245,536dbba14700aab274729d0d,login
2014-05-10 13:39:46,140326000797,536dbba14700aab274729cf6,login
2014-05-10 13:39:46,140328000993,536dbba14700aab274729d12,login
2014-05-10 13:39:46,140331001115,536dbba14700aab274729d10,login
2014-05-10 13:39:46,140325000744,536dbba04700aab274729ce0,login
2014-05-10 13:39:46,140328000982,536dbba14700aab274729d0a,login
2014-05-10 13:39:46,140331001063,536dbba04700aab274729ce3,login
2014-05-10 13:39:46,140331001067,536dbba14700aab274729d1c,login
2014-05-10 13:39:46,140401001157,536dbba04700aab274729ce8,login
2014-05-10 13:39:46,140408001216,536dbba14700aab274729cef,login
2014-05-10 13:39:46,140401001174,536dbba14700aab274729d27,login
2014-05-10 13:39:46,140306000215,536dbba04700aab274729cde,login
2014-05-10 13:39:46,140331001064,536dbba04700aab274729cdc,login
2014-05-10 13:39:46,140326000825,536dbba04700aab274729cd9,login
2014-05-10 13:39:46,140408001294,536dbba14700aab274729d0f,login
我希望将login前面的设备ID取出来,进行数量的统计,最后得到结果:
各个设备的累计登录次数
536dbba04700aab274729cdc 5
536dbba04700aab274729ce3 4
好,创建一个LogMapper类,该类负责做数据的Map,前两各模板参数用于KeyIn和ValueIn, 后两个模板参数用于KeyOut和ValueOut,都是代表类型。
假定一个<KeyIn, ValueIn>组成一个pair,输入的很多pair在一个组里面, 这些pair被一定的算法Map之后,会变成很多组pair。
官方文档:http://hadoop.apache.org/docs/r2.4.1/api/org/apache/hadoop/mapreduce/Mapper.html
Maps input key/value pairs to a set of intermediate key/value pairs.注意,这里的Mapper类用的包是mapreduce,以前有一个老的叫mapred。
这里介绍了两者的区别:
http://stackoverflow.com/questions/7598422/is-it-better-to-use-the-mapred-or-the-mapreduce-package-to-create-a-hadoop-job
LongWritable和IntWritable是两个类,用于帮助创建可以Long和Int类型的变量。它们能够帮助将Long和Int的值序列化成字节流,因此都有两个关键方法读入和写出:
void | readFields(DataInput in) Deserialize the fields of this object from in. |
void | write(DataOutput out) Serialize the fields of this object to out. |
我的Mapper代码:
package org.freebird.mapper;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
public class LogMapper
extends Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable ONE = new IntWritable(1);
public void map(Object key, Text value, org.apache.hadoop.mapreduce.Mapper.Context context) throws IOException, InterruptedException {
String[] line = value.toString().split(",");
if (line.length == 4) {
String dId = line[2];
context.write(new Text(dId), ONE);
}
}
}
这个Mapper的子类覆盖了map函数,将字符串用,号拆开后,取出第三个元素作为设备ID, 然后作为key写入context对象。这里value设置为1, 因为后面reduce阶段会简单的求和。
Context类文档参考: http://hadoop.apache.org/docs/r1.1.1/api/org/apache/hadoop/mapreduce/Mapper.Context.html
write方法不是一般概念的hasmap添加key,value,而是生成一个新的pair对象,里面包含了key和value。 如果多个key相同,也会产生多个pair对象,交给reduce阶段处理。
相关文章推荐
- MapReduce 编程 系列三 编写简单reducer
- 跟我从头学TAO编程系列 (2) -- 编写最简单的TAO应用程序
- 跟我从头学TAO编程系列 (2) -- 编写最简单的TAO应用程序
- 从头学TAO编程系列 编写最简单的TAO应用程序
- 笨鸟先飞学编程系列之二 基础代码的编写3(转)
- 如何使用Python为Hadoop编写一个简单的MapReduce程序
- DirectShow基础编程 最简单transform filter 编写步骤
- 调用DirectX进行简单的多媒体编程系列(三)
- 如何使用Python为Hadoop编写一个简单的MapReduce程序(这个人T字还有好几篇精华的可以看)
- 笨鸟先飞学编程系列之二 基础代码的编写2(转)
- Ophone/OMS编程:编写JIL Widget的一个最简单的例子:hello world。
- Web服务初探:用Demo学Web服务系列(2)——编写一简单的Web服务
- Hadoop系列之三:函数式编程语言和MapReduce
- HDOJ4500 小Q系列故事——屌丝的逆袭(简单模拟) &&腾讯2013编程马拉松第0场第一题
- Linux 网络编程一步一步学(一)-简单客户端编写
- JMS&MQ系列之简单JMS应用程序编写步骤
- 调用DirectX进行简单的多媒体编程系列(二)
- 调用DirectX进行简单的多媒体编程系列(一)
- DirectShow基础编程 最简单的源Filter的编写步骤
- DirectShow基础编程 最简单的源Filter的编写步骤