Hadoop之MapReduce

在Hadoop中,MapReduce起着非常重要的数据处理作用。HDFS作为数据存储的核心部件起着管理文件资源的作用,而MapReduce作为一种编程计算模型,对数据的分析和处理任务进行调度管理。

在MapReduce中,所有的机器分成两个角色,一个叫JobTracker,另外一个叫TaskTracker。同HDFS的分布式概念一样,JobTracker是用于执行总体调度的,一般运行在NameNode机器上,而TaskTracker则负责在节点DataNode上执行具体的分布式任务的计算。海量的数据的计算任务就被许多个TaskTracker将计算量分布在每一个节点上,从而最大程度的利用资源。

在MapReduce的入门也有一个HelloWord的例子,源代码如下:

package com.ant.ren.hadoop.demo;

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

public class WordCount extends Configured implements Tool{
	/**
	* you can create any class extends Mapper stand for map
	* in map stage, we just split input file content by StringTokenizer default token: whitespace
	* then use word as key, show up count (1) as value
	**/
	public static class Map extends Mapper<LongWritable, Text, Text, IntWritable>{
		private final static IntWritable one = new IntWritable(1);
		private Text word = new Text();
		
		public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
			String line = value.toString();
			StringTokenizer tokenizer = new StringTokenizer(line);
			
			while(tokenizer.hasMoreElements()){
				word.set(tokenizer.nextToken());
				context.write(word, one);
			}
		}
	}
	
	/**
	* you can create any class extends Reducer stand for reduce
	* in reduce stage, we iterate value for the same key (word), calculate the sum of their values
	* then output <word, sum> as reduce result
	**/
	public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable>{
		public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException{
			int sum = 0;
			for(IntWritable val : values)
				sum += val.get();
			context.write(key, new IntWritable(sum));
		}
	}
	
	@Override
	public int run(String[] args) throws Exception {
		Job job = new Job(getConf());
		job.setJarByClass(WordCount.class);
		job.setJobName("Word Count Job");
		
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(IntWritable.class);
		
		job.setMapperClass(Map.class);
		job.setReducerClass(Reduce.class);
		
		job.setInputFormatClass(TextInputFormat.class);
		job.setOutputFormatClass(TextOutputFormat.class);
		
		FileInputFormat.setInputPaths(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		
		boolean success = job.waitForCompletion(true);
		return success ? 0 : 1;
	}
	
	public static void main(String[] args) throws Exception{
		int ret = ToolRunner.run(new WordCount(), args);
		System.exit(ret);
	}	
}

它演示的是对于输入的两个文件,统计它们内容里每一个单词出现的次数,并输出一张统计结果。例如给定这样两个文件的输入:

"file-1"
hello world hello everyone

"file-2"
hello hadoop goodbye hadoop

那么输出的统计结果将会是这个样子:

hello 4
world 1
everyone 1
hadoop 2

在Hadoop中,每个MapReduce任务都被初始化为一个Job。每个Job又可以分为两个阶段:map阶段和reduce阶段。在map阶段,由map函数会接受一个如<key,value>形式的输入,然后产生一个<key, value>形式的中间输出。Hadoop会将所有具有相同key值的<key, value>输入集合到一起,传递给第二阶段的reduce函数,所以reduce函数看到的将不是<key, value>,而是<key, list of values>。第二阶段的reduce函数会对这个每个<key, list of values>进行处理,然后选择产生0个或1个最终的<key, value>输出。之所有选择类似map输出的<key, value>形式作为reduce输出也是考虑到这样的输出不需要处理就可以直接作为下一个map的输入,这样的模型最终可以方便对海量数据进行多重处理和分析。(易于实现和扩展)

 

在运行这个例子的时候,其实没必要把输入文件上传到Hadoop的HDFS里面去,如果只是为了根据自己需求调试和设计MapReduce的模型,只要机器上启动了MapReduce,没启动HDFS都可以。输入的话MapReduce程序会讲当前工作目录当做起点来搜索输入的数据。举例来说,就运行这个WordCount例子,就在当前工作目录下建一个目录:input,然后将file-1和file-2放入input目录中就可以运行:java WordCount input output,最终会在当前目录下创建output目录和结果文件的。当然如果用户遵循官方或者书上的例子用bin/hadoop -jar命令来运行的话,搜索input的起点就成了HDFS文件系统内部,需要先把input和file-1,file-2先用HDFS命令上传到HDFS中去。(如果有集群环境的话,可以file-1和file-2放在不同的节点机器上来观察效果)

 

其实MapReduce的模型简单易懂,但是运用起来还是很多经验和讲究的。比如如果要做到对海量同源数据进行分析和归类:例如淘宝网需要分析购买某种商品的用户还喜欢购买哪些别的商品,帮助用户找到志趣相投的其他用户或者卖家。在使用MapReduce进行数据分析挖掘的时候,如何选取key是相当重要的,key选择得当,可以让数据本身得到合并并在reduce中来进行统计。这就有点像SQL语句中的表连接,如果选取join的column对于分析的效率和结果集的大小、正确性都是至关重要的。


 

你可能感兴趣的:(Hadoop之MapReduce)