非Java实现MapReduce

来源:互联网 发布:知乎 李云迪前妻 编辑:程序博客网 时间:2024/04/28 04:37

hadoop的编程模型其实就是mapper和reducer,由于Hadoop是由Java比编写的,所以用Java来写任务就非常自然,但是每次都得打包上传,用起来有点不方便。


hadoop提供了工具:hadoop streaming。mapper和reducer从stdin和stdout中读取用户数据,逐行处理之后,再发送给标准输入输出。streaming工具会创建mapreduce作业,发送给各个tasktracker,同时监控整个作业的执行过程。


mapper启动时,会将脚本作为一个单独的进程启动。

mapper运行时,会把输入切分成行,并把每一行提供给可执行文件进程的标准输入。

mapper收集可执行文件标准输出的内容,并把每一行换成key/value对,作为mapper的输出(默认情况下,一行中第一个tag之前的部分作为key,之后的部分作为value,如果没有tag,那么整行为key,null为value)。


reducer与mapper类似。用perl写mapper的时候可以这样:

#!/usr/bin/perl -wMAIN:{while (my $line = <STDIN>) {chomp($line);next unless (length($line) > 0);my @fields = split(/\t/, $line);...}}

reducer的代码也类似。考虑一个实际的问题:通过user_id来join两个用户表,mapper得到的是两种都包含user_id的记录,那么在输出的时候可以是这样的:

print user_id."\t".userInfo."\n";

这样reducer中会把相同的user_id对应的不同的userInfo聚集起来。如果本来的数据就是符合这种格式的,那么,直接用cat就可以来作为mapper(或者reducer)。


这里介绍几个hadoop streaming相关的配置:

1、stream.map.output.field.separator:map的输出中key、value的分隔符。

2、stream.num.map.output.key.fields:分隔符的位置,之前的作为key,之后的作为value。

3、map.output.key.field.separator:map输出中key内部的分隔符。

4、num.key.fields.for.partition:指定分桶时,key按照分隔符切割后,其中用于分桶key所占的列数。

5、stream.reduce.output.field.separator:设置reduce输出中key和value的分隔符。

6、stream.num.reduce.output.key.fields:设置reduce程序分隔符的位置。


还有一个很有用的设置:

-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner 
在map和reduce还有一个patition的过程,使用KeyFieldBasedPartitioner可以方便地实现二次排序。比如map的输出为id.'\t'.sortkey.'\t'.value.'\n',此时设置:

num.key.fields.for.partition = 1

stream.num.map.output.key.fields = 2

那么就可以实现将map的输出根据id输出给不同的reducer,每个reducer接受的到的是根据sorkkey排序的。


到这里大家也应该清楚,如果使用c/c++或者是其他的什么语言来写,都是类似的写法。