WordCount计数--第一个MapReduce程序

来源:互联网 发布:淘宝交易指数 构成 编辑:程序博客网 时间:2024/06/05 15:58

最简单的MapReduce应用程序至少包含 3 个部分:一个 Map 函数、一个 Reduce 函数和一个 main 函数。在运行一个mapreduce计算任务时候,任务过程被分为两个阶段:map阶段和reduce阶段,每个阶段都是用键值对(key/value)作为输入(input)和输出(output)。main 函数将作业控制和文件输入/输出结合起来。


并行读取文本中的内容,然后进行MapReduce操作


  • Map过程:并行读取文本,对读取的单词进行map操作,每个词都以<key,value>形式生成。

我的理解:

  一个有三行文本的文件进行MapReduce操作。

  读取第一行Hello World Bye World ,分割单词形成Map。

  <Hello,1> <World,1> <Bye,1> <World,1>

  读取第二行Hello Hadoop Bye Hadoop ,分割单词形成Map。

  <Hello,1> <Hadoop,1> <Bye,1> <Hadoop,1>

  读取第三行Bye Hadoop Hello Hadoop,分割单词形成Map。

  <Bye,1> <Hadoop,1> <Hello,1> <Hadoop,1>


  • Reduce操作是对map的结果进行排序,合并,最后得出词频。

  经过进一步处理(combiner),将形成的Map根据相同的key组合成value数组。

  <Bye,1,1,1> <Hadoop,1,1,1,1> <Hello,1,1,1> <World,1,1>

  循环执行Reduce(K,V[]),分别统计每个单词出现的次数。

  <Bye,3> <Hadoop,4> <Hello,3> <World,2>


WordCount程序:

package mr;import java.io.IOException;import java.net.URI;import java.util.Iterator;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FileSystem;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.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;   public class MyWordCount {static class MyMapper  extends  Mapper<LongWritable, Text, Text, IntWritable>{     /**IntWritable, Text 均是 Hadoop 中实现的用于封装 Java 数据类型的类,这些类实现了WritableComparable接口,       *都能够被串行化从而便于在分布式环境中进行数据交换,你可以将它们分别视为int,String 的替代品。       *Context:收集Mapper输出的<k,v>对。       *Context的write(k, v)方法:增加一个(k,v)对到context       *程序员主要编写Map和Reduce函数.这个Map函数使用StringTokenizer函数对字符串进行分隔,通过write方法把单词存入word中        *write方法存入(单词,1)这样的二元组到context中*/ public void map(LongWritable k1, Text v1, Context context)  throws java.io.IOException, java.lang.InterruptedException {String[]  lines= v1.toString().split("\\s+");for(String word: lines){context.write(new Text(word), new IntWritable(1));}System.out.println("map......"); }}static class  MyReduce extends Reducer<Text, IntWritable, Text, IntWritable>{ public void reduce(Text key, Iterable<IntWritable> values, Context context) throws java.io.IOException, java.lang.InterruptedException { int sum=0;  Iterator<IntWritable>  it=values.iterator();  //it是一个集合 while(it.hasNext()){sum+= it.next().get();    //it.next()是一个泛型--IntWritable,用get()方法把它转换成int类型 } context.write(key, new IntWritable(sum));      System.out.println("reduce......"); }    }private static String INPUT_PATH="hdfs://master:9000/input/1.txt";private static String OUTPUT_PATH="hdfs://master:9000/output/c/";public static void main(String[] args) throws Exception {Configuration  conf=new Configuration();FileSystem  fs=FileSystem.get(new URI(OUTPUT_PATH),conf);  //如果路径中的文件存在,则自动删除,重新创建输出文件if(fs.exists(new Path(OUTPUT_PATH)))fs.delete(new Path(OUTPUT_PATH));Job  job=new Job(conf,"myjob");//创建一个jobjob.setJarByClass(MyWordCount.class);//通过传入的class 找到job的jar包job.setMapperClass(MyMapper.class);//设置map/reducer处理类 job.setReducerClass(MyReduce.class); job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);job.setCombinerClass(MyReduce.class); //设置Combine处理类 FileInputFormat.addInputPath(job,new Path(INPUT_PATH));FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));job.waitForCompletion(true);//Job运行,true表示将运行进度等信息及时输出给用户,false的话只是等待作业结束}}


map函数:

public void map(LongWritable k1, Text v1, Context context)                          throws java.io.IOException, java.lang.InterruptedException
k1,v1 就是输入的key和value,第三个参数Context context是可以记录输入的key和value,例如:context.write(new Text(word), new IntWritable(1));此外contex还会记录map运算分状态。
reduce函数:
 
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws java.io.IOException, java.lang.InterruptedException
reduce函数的输入也是一个key/value的形式,不过它的value是一个迭代器的形式Iterable<Intwritable》 values,也就是说reduce的输入是一个key对应一组的值的value。
main函数:
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包下的配置文件里。
  Job  job=new Job(conf,"myjob");  
构建一个job,在mapreduce框架里一个mapreduce任务也叫mapreduce作业也叫做一个mapreduce的job,而具体的map和reduce运算就是task了,这里我们构建一个job,构建时候有两个参数,一个是conf这个就不累述了,一个是这个job的名称。
 job.setJarByClass(MyWordCount.class); 
装载程序员编写好的计算程序,例如我们的程序类名就是WordCount了。虽然我们编写mapreduce程序只需要实现map函数和reduce函数,但是实际开发我们要实现三个类,第三个类是为了配置mapreduce如何运行map和reduce函数,准确的说就是构建一个mapreduce能执行的job了,例如WordCount类。
job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);
定义输出的key/value的类型,也就是最终存储在hdfs上结果文件的key/value的类型。

原创粉丝点击