MapReduce采用的是“
分而治之
”的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个从节点共同完成,然后通过整合各个节点的中间结果,得到最终结果。简单来说,MapReduce就是”任务的分解与结果的汇总
“。
MapReduce是Google公司发明的
一种面向大规模海量数据处理的高性能并行计算平台和软件编程框架
,是目前最为成功和最易于使用的大规模海量数据并行处理技术
,广泛应用于搜索引擎(文档倒排索引,网页链接图分析与页面排序等)、Web日志分析、文档分析处理、机器学习、机器翻译等各种大规模数据并行计算应用领域
a.如何对付大数据:分而治之
对相互间不具有计算依赖关系的大数据,实行并行最自然的方式就是分而治之。
b.上升到抽象模型:Mapper和Reducer
MPI等并行计算方式缺少高层并行编程模型,为了克服这一缺陷,MapReduce借鉴了Lisp函数式语言中的思想,用Map和Reduce两个函数提供了高层的并行编程抽象模型。
c.上升到构架:统一构架,为程序员隐藏系统细节
MPI等并行计算方法缺少统一的计算框架支持,程序员需要考虑数据存储、划分、分发、结果收集、错误恢复等诸多细节;为此,MapReduce设计并提供了统一的计算框架,为程序员隐藏了绝大多数系统层面的处理细节
在分布式计算中,MapReduce框架负责处理了并行编程里分布式存储、工作调度,负载均衡、容错处理以及网络通信等复杂问题,现在我们把处理过程高度抽象为Map与Reduce两个部分来进行阐述,其中Map部分负责把任务分解成多个子任务,Reduce部分负责把分解后多个子任务的处理结果汇总起来
map部分:
map: (k1; v1) [(k2; v2)]
输入:键值对(k1; v1)表示的数据
处理:文档数据记录(如文本文件中的行,或数据表格中的行)将以“键值对”形式传入map函数;map函数将处理这些键值对,并以另一种键值对形式输出处理的一组键值对中间结果[(k2; v2)]
输出:键值对[(k2; v2)]表示的一组中间数据
reduce部分:
reduce: (k2; [v2]) [(k3; v3)]
输入: 由map输出的一组键值对[(k2; v2)] 将被进行合并处理将同样主键下的不同数值合并到一个列表[v2]中,故reduce的输入为(k2; [v2])
处理:对传入的中间结果列表数据进行某种整理或进一步的处理,并产生最终的某种形式的结果输出[(k3; v3)] 。
输出:最终输出结果[(k3; v3)]
Linux Ubuntu 14.0
jdk-7u75-linux-x64
hadoop-2.6.0-cdh5.4.5
hadoop-2.6.0-eclipse-cdh5.4.5.jar
eclipse-java-juno-SR2-linux-gtk-x86_64
1.切换目录到/apps/hadoop/sbin下,启动hadoop。
cd /apps/hadoop/sbin
./start-all.sh
2.在linux上,创建一个目录/data/mapreduce1。
mkdir -p /data/mapreduce1
3.创建/data/mapreduce1/file,
内容为:
China is my motherland
I love China
I am from China
4.将linux本地/data/mapreduce1/wordcount,上传到HDFS上的/mymapreduce1/in目录下。若HDFS目录不存在,需提前创建。
hadoop fs -mkdir -p /mymapreduce1/in
hadoop fs -put /data/mapreduce1/file /mymapreduce1/in
5.打开Eclipse,File–>New–>Other–>Map/Reduce Project,项目名可以随便取,如WordCount。导入所需的jar包(不详述!)
6.编写代码
(1).Mapper部分代码:
期望的Map输出类型为<单词,出现次数>
Map输入类型为
Map输入类型最终确定为//vlaue为Text类型,指每次读入文件的一行
Map输出类型最终确定为
public static class doMapper extends Mapper<Object, Text, Text, IntWritable>{
//第一个Object表示输入key的类型;第二个Text表示输入value的类型;第三个Text表示表示输出键的类型;第四个IntWritable表示输出值的类型
public static final IntWritable one = new IntWritable(1);
public static Text word = new Text();
@Override
protected void map(Object key, Text value, Context context) throws IOException, InterruptedException //抛出异常
{
StringTokenizer tokenizer = new StringTokenizer(value.toString(),"\t");
//StringTokenizer是Java工具包中的一个类,用于将字符串进行拆分
word.set(tokenizer.nextToken());
//返回当前位置到下一个分隔符之间的字符串
context.write(word, one);
//将word存到容器中,记一个数
}
}
代码解释:
在map函数里有三个参数,前面两个Object key,Text value就是输入的key和value,第三个参数Context context是可以记录输入的key和value。例如context.write(word,one);此外context还会记录map运算的状 态。map阶段采用Hadoop的默认的作业输入方式,把输入的value用StringTokenizer()方法截取出的单词设置为key, 设置value为1,然后直接输出value>。
Reducer代码:
public static class doReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
//参数同Map一样,依次表示是输入键类型,输入值类型,输出键类型,输出值类型
private IntWritable result = new IntWritable();
@Override
protected void reduce(Text key, Iterable values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
//for循环遍历,将得到的values值累加
result.set(sum);
context.write(key, result);
}
}
解释:
map输出的<key,value>先要经过shuffle过程把相同key值的所有 value聚集起来形成<key,values>后交给reduce端。reduce端接收到<key,values>之后,将 输入的key直接复制给输出的key,用for循环遍历values并求和,求和结果就是key值代表的单词出现的总次,将其设置为value,直接输 出<key,value>。
所导入包:
mport java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
主函数:
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
Job job = Job.getInstance();
job.setJobName("WordCount");
job.setJarByClass(WordCount.class);
job.setMapperClass(doMapper.class);
job.setReducerClass(doReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
Path in = new Path("hdfs://localhost:9000/mymapreduce1/in/file");
Path out = new Path("hdfs://localhost:9000/mymapreduce1/out");
FileInputFormat.addInputPath(job, in);
FileOutputFormat.setOutputPath(job, out);
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
7.在WordCount类文件中,单击右键=>Run As=>Run on Hadoop选项,将MapReduce任务提交到Hadoop中。
8.待执行完毕后,打开终端或使用hadoop eclipse插件,查看hdfs上,程序输出的实验结果。
hadoop fs -ls /mymapreduce1/out
hadoop fs -cat /mymapreduce1/out/part-r-00000
9.执行结果为:
I 2
is 1
China 3
my 1
love 1
am 1
from 1
motherland 1