wordcount代码实现详解

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.hadoop.examples;
//导入必要的package
import java.io.IOException;        //报错类
import java.util.StringTokenizer;  //StringTokenizer类,用于将空白字符作为分割符的类

import org.apache.hadoop.conf.Configuration;//Hadoop中用于读取配置信息的类
import org.apache.hadoop.fs.Path;           //有关文件系统输入输出数据的类
import org.apache.hadoop.io.IntWritable;    //封装定义了IntWritable类
import org.apache.hadoop.io.Text;           //封装定义了Text类
import org.apache.hadoop.mapreduce.Job;     //封装定义了Job类
import org.apache.hadoop.mapreduce.Mapper;  //封装定义了Mapper类
import org.apache.hadoop.mapreduce.Reducer; //封装定义了Reducer类
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;   //文件输入要用到的类
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; //文件输出要用到的类
import org.apache.hadoop.util.GenericOptionsParser;             //GenericOptionsParser类,用来解释常用hadoop命令,并根据需要为Configuration对象设置相应的值

public class WordCount {

  public static class TokenizerMapper
       extends Mapper<Object, Text, Text, IntWritable>{         //自定义的TokenizerMapper类,继承自前面导入的Mapper类

    private final static IntWritable one = new IntWritable(1);  //实例化了一个IntWritable类的one对象并赋值为常量1
    private Text word = new Text();                             //实例化了一个Text类的对象word

    public void map(Object key, Text value, Context context     //定义Map方法
                    ) throws IOException, InterruptedException {

//这里说一下context类,它是Mapper的一个内部类,它用来与MapReduce系统进行通信,如把map的结果传给reduce处理。简单的说顶级接口用它在map或是reduce任务中跟踪task的状态,MapContext就是记录了map执行的上下文,在mapper类中,这个context可以存储一些job conf的信息,同时context作为了map和reduce执行中各个函数的一个桥梁,我们可以在map函数中处理这个信息

      StringTokenizer itr = new StringTokenizer(value.toString());//实例化了一个以空白字符为分隔符的StringTokenizer类的对象itr
      while (itr.hasMoreTokens()) {//如果判断还有下一个分隔符(空格)
        word.set(itr.nextToken()); //则输出并返回之间的字符串给word
        context.write(word, one);  //context.write方法将(word,1)这样的二元组存入context中
      }
    }
  }

  public static class IntSumReducer                           //自定义的IntSumReducer类,继承自前面导入的Reducer类
       extends Reducer<Text,IntWritable,Text,IntWritable> {
    private IntWritable result = new IntWritable();           //实例化了一个IntWritable类的result对象

    public void reduce(Text key, Iterable<IntWritable> values,Context context//定义Reduce方法,这里迭代器(Iterator)是一种设计模式,它是一个对象,它可以遍历并选择序列(IntWritable)中的对象,而开发人员不需要了解该序列的底层结构。
                       ) throws IOException, InterruptedException {
      int sum = 0;
      for (IntWritable val : values) {
        sum += val.get();//将该词的出现次数相加
      }
      result.set(sum);//将sum赋给result
      context.write(key, result);//输出最终结果
    }
  }

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
  //运行MapReduce程序前都要初始化Configuration,该类主要是读取MapReduce系统配置信息,这些信息包括hdfs还有MapReduce,也就是安装hadoop时候的配置文件例如:core-site.xml、hdfs-site.xml和mapred-site.xml等等文件里的信息,有些童鞋不理解为啥要这么做,这个是没有深入思考MapReduce计算框架造成,我们程序员开发MapReduce时候只是在填空,在map函数和reduce函数里编写实际进行的业务逻辑,其它的工作都是交给MapReduce框架自己操作的,但是至少我们要告诉它怎么操作啊,比如hdfs在哪里,MapReduce的jobstracker在哪里,而这些信息就在conf包下的配置文件里。

    String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
    if (otherArgs.length < 2) {
      System.err.println("Usage: wordcount <in> [<in>...] <out>");
      System.exit(2);
    }//If的语句好理解,就是运行WordCount程序时候一定是两个参数,如果不是就会报错退出。至于第一句里的GenericOptionsParser类,它是用来解释常用hadoop命令,并根据需要为Configuration对象设置相应的值
    Job job = Job.getInstance(conf, "word count");//用Job.getInstance方法设置作业名为word count
    job.setJarByClass(WordCount.class);           //为job的输出数据设置Key类
    job.setMapperClass(TokenizerMapper.class);    //设置Mapper类(Map阶段使用)
    job.setCombinerClass(IntSumReducer.class);    //设置Combiner类(中间合并结果)
    job.setReducerClass(IntSumReducer.class);     //设置Reducer类(Reduce阶段使用)
    job.setOutputKeyClass(Text.class);            //为job的输出数据设置Key类,规定Reduce输出的Key类型为Text
    job.setOutputValueClass(IntWritable.class);   //设置Reduce输出的Value类型为IntWritable

    for (int i = 0; i < otherArgs.length - 1; ++i) { //设置输入输出路径
      FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
    }
    FileOutputFormat.setOutputPath(job,
      new Path(otherArgs[otherArgs.length - 1]));
    System.exit(job.waitForCompletion(true) ? 0 : 1);//等待任务执行完毕退出
  }
}
时间: 2024-10-24 03:45:54

wordcount代码实现详解的相关文章

PHP扩展代码结构详解

PHP扩展代码结构详解: 这个是继:使用ext_skel和phpize构建php5扩展  内容 (拆分出来) Zend_API:深入_PHP_内核:http://cn2.php.net/manual/zh/internals2.ze1.php 我们使用ext_skel创建扩展 hello_module,该模块包含一个方法:hello_world. 使用ext_skel 生成的代码都是PHP_开头的宏, 而不是ZEND_开头. 实际上这两者是一样的. 在源代码src/main/PHP.h 中发现:

Spring基于事件驱动模型的订阅发布模式代码实例详解

代码下载地址:http://www.zuidaima.com/share/1791499571923968.htm 原文:Spring基于事件驱动模型的订阅发布模式代码实例详解 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): 当目标发送改变(发布),观察者(订阅者)就可以接收到改变: 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的

Spring整合JUnit框架进行单元测试代码使用详解

[转]Spring整合JUnit框架进行单元测试代码使用详解 转自 http://blog.csdn.net/yaerfeng/article/details/25187775 感谢博主 :云淡风轻 .仅此一抹 一.Spring提供的JUnit框架扩展: 1. AbstractSpringContextTests:spring中使用spring上下文测试的Junit扩展类,我们一般不会使用这个类来进行单元测试,它是spring内部设计使用到的类    2. AbstractDependencyI

java文本相似度计算(Levenshtein Distance算法(中文翻译:编辑距离算法))----代码和详解

算法代码实现: package com.util; public class SimFeatureUtil { private static int min(int one, int two, int three) { int min = one; if (two < min) { min = two; } if (three < min) { min = three; } return min; } public static int ld(String str1, String str2)

第52讲:Scala中路径依赖代码实战详解

<DT大数据梦工厂>大数据实战视频"Scala深入浅出实战经典"视频.音频和PPT下载!第52讲:Scala中路径依赖代码实战详解百度云:http://pan.baidu.com/s/1gdES4hX360云盘:http://yunpan.cn/ccHXX2Wkrrrt4 访问密码 c489腾讯微云:http://url.cn/VV5kx5 记录: Scala中内部类的路径依赖非常适合现在互联网看待事物所属关系,组织关系. 根据依赖的外部实例的不同,内部类类型会有所不同.由

网页代码上线详解

第1章 代码上线 早期手动部署代码 纯手动scp上传代码. 纯手动登陆,Git pull 或者SVN update. 纯手动xftp上传代码. 开发发送压缩包,rz上传,解压部署代码. 缺点: 全程运维参与,占用大量时间. 如果节点多,上线速度慢. 人为失误多,目录管理混乱. 回滚不及时,或者难以回退. 1.1 小型公司代码上线案例 1.1.1 特点及问题 01.发布快.及时,可随时随地发布代码 02.开发发布的代码不经测试,导致无法访问(如死循环代码),对网站用户体验较差 1.1.2 架构方案

Tomcat使用MyEclipse远程调试Java代码配置详解

Tomcat使用MyEclipse远程调试Java代码总结如下:在做远程调试时,在windows系统和非windows系统下的配置,Tomcat中会有所差别,具体如下: 第一步.配置tomcat一.在windows系统中:打开%CATALINE_HOME%/bin下的文件catalina.bat,加入下面这行:set CATALINA_OPTS=-server -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket

第33讲:List的一阶函数操作代码实战详解

操作的参数不是函数,就是一阶函数 我们通过具体的代码来说明: package com.dt.scala.dataset object ListFirstOrderOps {   def main(args: Array[String]): Unit = {     //列表合并,使用:::操作符     println(List(1,2):::List(3,4):::List(5,6))     println(List(1,2):::(List(3,4):::List(5,6)))     /

线程(代码实现)详解

在计算机科学中,一个线程执行的是,可以独立地被一个管理编程指令的最小序列调度,这是通常的的一部分的操作系统.线程和所述的实施过程的操作系统之间的不同,但在大多数情况下,一个线程的过程的一个组成部分.多个线程可以在一个过程中存在,执行同时和共享的资源,例如存储器,而不同的过程不共享这些资源.特别是,一个进程的线程共享其可执行代码和它的变量在任何给定时间的值. 具有单处理器系统通常实现由多线程时间分片:所述中央处理单元(CPU)的不同之间切换的软件线程.这种上下文切换通常发生非常频繁,并迅速不够,用