MapReduce是一种可用于数据处理的编程模型。该模型比较简单,但用于编写有用的程序并不简单。Hadoop可以运行由各种语言编写的MapReduce程序。例如:Java、Ruby、Python和C++语言等。最重要的是,MapReduce程序本质上是并行运行的,因此可以将大规模的数据分析任务交给任何一个拥有足够多机器的运行商。MapReduce的优势在于处理大规模数据集。
把万事万物都可以看做两个阶段来处理
map阶段
reduce阶段
如何写map
如何写reduce
python Ruby C++ …
Java语言为主
map阶段 可以开启多个map任务(线程)
map()函数
master,
slave,
YarnChild/TaskTracker(进程)
五个map任务(线程)
一个reduce任务(线程)
slave1,
YarnChild/TaskTracker(进程)
四个map任务(线程)
slave2,
YarnChild/TaskTracker(进程)
十个map任务(线程)
...
reduce阶段
reduce()
reduce 任务的个数取决于开发人员的设定 1个任务
slave,
YarnChild/TaskTracker(进程)
五个map任务(线程)
一个reduce任务(线程)
1、从MapReduce自身的命名特点可以看出,MapReduce由两个阶段组成:Map和Reduce。用户只需map()和reduce()两个函数,即可完成简单的分布式程序设计。
2、map()函数以key/value对作为输入,产生另外一系列key/value对作为中间输出写入本地磁盘。MapReduce框架会自动将这些中间数据按照key值进行聚合,且key值相同的数据被统一交给reduce()函数处理。
3、reduce()函数以key及对应的value列表作为输入,经合并key相同的value值后,产生另外一系列key/value对作为最终输出写入HDFS。
易于编程
良好的扩展性
高容错性
统计词频
public class WordsCount {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
if(args==null || args.length<2){
System.out.println("please input main method's parameters");
System.exit(0);
}
String inputPath = args[0];
String outputPath = args[1];
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, WordsCount.class.getSimpleName());
job.setJarByClass(WordsCount.class);
FileInputFormat.addInputPath(job, new Path(inputPath));
FileOutputFormat.setOutputPath(job, new Path(outputPath));
job.setMapperClass(WordsMapper.class);
job.setReducerClass(WordsReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//提交作业
job.waitForCompletion(true);
}
}
class WordsMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
public void map(LongWritable key, Text value, Context context) throws IOException,InterruptedException {
String wordsLine = value.toString();
String[] words = wordsLine.split(" ");
for(String word : words){
context.write(new Text(word), new IntWritable(1));
}
}
}
class WordsReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException{
int sum = 0;
for(IntWritable value : values){
sum += value.get();
}
context.write(key, new IntWritable(sum));
}
}
用户编写完MapReduce程序后,按照一定的规则指定程序的输入和输出目录,并提交到Hadoop集群中,作业在Hadoop中的执行过程如图所示。Hadoop将输入数据切分成若干个输入分片(input split),并将每个split交给一个Map Task处理;Map Task不断的从对应的split中解析出一个个key/value,并调用map()函数处理,处理完之后根据Reduce Task个数将结果分成若干个分区(partition)写到本地磁盘;同时,每个Reduce Task从每个Map Task上读取属于自己的那个partition,然后基于排序的方法将key相同的数据聚集在一起,调用reduce()函数处理,并将结果输出到文件中。
1、Client
用户编写的MapReduce程序通过Client提交到JobTracker端;同时,用户可通过Client提供的一些接口查看作业的运行状态。在Hadoop内部用“作业”(Job)表示MapReduce程序。一个MapReduce程序可对应若干个作业,而每个作业会被分解成若干个Map/Reduce任务(Task)。
2、JobTracker
JobTracke负责资源监控和作业调度。JobTracker 监控所有TaskTracker 与job的健康状况,一旦发现失败,就将相应的任务转移到其他节点;同时,JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器,而调度器会在资源出现空闲时,选择合适的任务使用这些资源。在Hadoop 中,任务调度器是一个可插拔的模块,用户可以根据自己的需要设计相应的调度器。
3、TaskTracker
TaskTracker 会周期性地通过Heartbeat 将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等)。TaskTracker 使用槽“slot”等量划分本节点上的资源量。“slot”代表计算资源(CPU、内存等)。一个Task 获取到一个slot 后才有机会运行,而Hadoop 调度器的作用就是将各个TaskTracker 上的空闲slot 分配给Task 使用。slot 分为Map slot 和Reduce slot 两种,分别供MapTask 和Reduce Task 使用。TaskTracker 通过slot 数目(可配置参数)限定Task 的并发度。
4、Task
Task 分为Map Task 和Reduce Task 两种,均由TaskTracker 启动。HDFS 以固定大小的block 为基本单位存储数据,而对于MapReduce 而言,其处理单位是split。split 是一个逻辑概念,它只包含一些元数据信息,比如数据起始位置、数据长度、数据所在节点等。它的划分方法完全由用户自己决定。但需要注意的是,split 的多少决定了Map Task 的数目,因为每个split 只会交给一个Map Task 处理。
Map Task 执行过程如下图 所示。由该图可知,Map Task 先将对应的split 迭代解析成一个个key/value 对,依次调用用户自定义的map() 函数进行处理,最终将临时结果存放到本地磁盘上,其中临时数据被分成若干个partition,每个partition 将被一个Reduce Task 处理。
Reduce Task 执行过程如下图所示。该过程分为三个阶段:
①从远程节点上读取MapTask 中间结果(称为“Shuffle 阶段”);
②按照key 对key/value 对进行排序(称为“Sort 阶段”);
③依次读取
数据源
数据字段描述
条件过滤
public class UidAndRecordIncludeKeyword {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
if(args==null || args.length<2){
System.out.println("please input main method' parameters");
System.exit(0);
}
System.out.println(args[0]);
String inputPath = args[0];
String outputPath = args[1];
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, UidAndRecordIncludeKeyword.class.getSimpleName());
job.setJarByClass(UidAndRecordIncludeKeyword.class);
job.setMapperClass(MyMapper.class);
job.setReducerClass(MyReducer.class);
FileInputFormat.addInputPath(job, new Path(inputPath));
FileOutputFormat.setOutputPath(job, new Path(outputPath));
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
job.waitForCompletion(true);
}
}
class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] field = line.split("\t");
if(field!=null && field.length==6){
String record = field[2];
if(record.indexOf("仙剑奇侠传")>=0){
context.write(new Text(field[1]), new Text(field[2]));
}
}
}
}
class MyReducer extends Reducer<Text,Text,Text,Text>{
public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
StringBuilder sb = new StringBuilder();
for(Text value : values){
sb.append(value.toString());
}
context.write(key, new Text(sb.toString()));
}
}
public class Sogou500wDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
if(args==null && args.length<2){
System.out.println("please input main method' parameters");
System.exit(0);
}
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, Sogou500wDemo2.class.getSimpleName());
job.setJarByClass(Sogou500wDemo2.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.setMapperClass(MyMapper2.class);
job.setReducerClass(MyReducer2.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// job.setNumReduceTasks(10);
job.waitForCompletion(true);
}
}
class MyMapper2 extends Mapper<LongWritable, Text, Text, IntWritable> {
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] fields = line.split("\t");
if(fields!=null && fields.length==6){
int rank = Integer.parseInt(fields[3]);
int order = Integer.parseInt(fields[4]);
if(rank<3 && order>2){
context.write(new Text(fields[1]), new IntWritable(1));
}
}
}
}
class MyReducer2 extends Reducer<Text, IntWritable, Text, IntWritable>{
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values){
sum += value.get();
}
context.write(key, new IntWritable(sum));
}
}