第一个完整的Map/Reduce小程序

来源:互联网 发布:centos 7 重置密码 编辑:程序博客网 时间:2024/06/06 10:01


          从在自己的win7下面装好虚拟机,然后在虚拟机上面安装hadoop,然后再安装hadoop-eclipse插件,过去好像有一个星期了,之前装虚拟机和hadoop都没成功,上个星期解除了封印,一口气把hadoop学习前期的所有的东西都搞定了,接下来就是遥遥无期的hadoop之路。希望自己能坚持下去。

         今天按着别人的思路在win7下面的eclipse里面敲了算是处女作的Map/Reduce程序,虽然很简单,但是自己还是一步一步的走通了,因为hadoop是安装在虚拟机上的,但是eclipse是在win7下面,所以在中间运行的时候会有一系列的错误,昨天晚上把遇到的问题百度的百度,问神的问神,烧香的烧香,基本上都解决了,现在能把程序跑起来,感觉自己的熬夜什么的都没有白费

          下面把一个完整的Map/Reduce程序贴出来,算是一个开始,也是一个纪念嘛!

     

        问题描述:

        先上数据:

         13599999999 10086

         13899999999      120

         13944444444 110

         13722222222 110

         18800000000 120

         13722222222 10086

         18944444444 10086

        

         要求是把拨打过同一个电话的电话输出来比如:

          110 13944444444,13722222222

         

         接下来就是Map/Reduce函数,Map函数将每一行数据读入,然后进行分割,分割成<key,value>的格式         上面的key相当于110value相当于13944444444,也就是数据前面的是value,后面的是key,代码如下:

     

Java代码  收藏代码
  1. public static class Map extends Mapper<LongWritable, Text, Text, Text> {  
  2.   
  3.         public void map(LongWritable key, Text value, Context context)  
  4.                 throws IOException, InterruptedException {  
  5.   
  6.             String line = value.toString(); // 读取源数据  
  7.   
  8.             try {  
  9.                 // 数据处理  
  10.                 String[] lineSplit = line.split(" "); // 将数据分割  
  11.                 String anum = lineSplit[0];  
  12.                 String bnum = lineSplit[1];  
  13.   
  14.                 context.write(new Text(bnum), new Text(anum)); // 输出  
  15.   
  16.             } catch (java.lang.ArrayIndexOutOfBoundsException e) {  
  17.                 context.getCounter(Counter.LINESKIT).increment(1); // 出错令计数器加1  
  18.                 return;  
  19.             }  
  20.   
  21.         }  
  22.   
  23.     }  

 

 

    接下就是Reduce类,Reduce类要做的就是把从Map传入来的数据进行整合,将Map中具有相同key值的value    进行迭代,代码如下(需要知道的是,Map函数的输出也就是Reduce函数的输入,所以在写里面的reduce函     数的时候要注意参数的类型要和上面Map的输出值的类型相对应):

 

Java代码  收藏代码
  1. public static class Reduce extends Reducer<Text, Text, Text, Text> {  
  2.           
  3.         //Iterable<> 使用一个迭代器将数据保存起来  
  4.         public void reduce(Text key,Iterable<Text> values,Context context) throws IOException, InterruptedException {  
  5.             String valueString;  
  6.             String out = "";  
  7.               
  8.             for(Text value : values) {  
  9.                 valueString = value.toString();  
  10.                 out += valueString+",";  
  11.             }  
  12.               
  13.             context.write(key, new Text(out));  
  14.         }  
  15.     }  

 

 

     接下来就是贴出整个程序,里面有个枚举是用来记录数据错误的时候进行一个计数,还有一个run方法是重写     了主类实现的接口的方法,每个Map/Reduce程序里面run方法里面书写的套路基本上都是一样的,main方       法里面书写的套路基本上也都是一样的,只要改一下主类的名字就可以了

  

Java代码  收藏代码
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.conf.Configured;  
  5. import org.apache.hadoop.fs.Path;  
  6. import org.apache.hadoop.io.LongWritable;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.mapreduce.Job;  
  9. import org.apache.hadoop.mapreduce.Mapper;  
  10. import org.apache.hadoop.mapreduce.Reducer;  
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  13. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  14. import org.apache.hadoop.util.Tool;  
  15. import org.apache.hadoop.util.ToolRunner;  
  16.   
  17. public class Test_2 extends Configured implements Tool {  
  18.     enum Counter {  
  19.         LINESKIT, // 出错的行  
  20.     }  
  21.   
  22.     public static class Map extends Mapper<LongWritable, Text, Text, Text> {  
  23.   
  24.         public void map(LongWritable key, Text value, Context context)  
  25.                 throws IOException, InterruptedException {  
  26.   
  27.             String line = value.toString(); // 读取源数据  
  28.   
  29.             try {  
  30.                 // 数据处理  
  31.                 String[] lineSplit = line.split(" "); // 将数据分割  
  32.                 String anum = lineSplit[0];  
  33.                 String bnum = lineSplit[1];  
  34.   
  35.                 context.write(new Text(bnum), new Text(anum)); // 输出  
  36.   
  37.             } catch (java.lang.ArrayIndexOutOfBoundsException e) {  
  38.                 context.getCounter(Counter.LINESKIT).increment(1); // 出错令计数器加1  
  39.                 return;  
  40.             }  
  41.   
  42.         }  
  43.   
  44.     }  
  45.       
  46.     public static class Reduce extends Reducer<Text, Text, Text, Text> {  
  47.           
  48.         //Iterable<> 使用一个迭代器将数据保存起来  
  49.         public void reduce(Text key,Iterable<Text> values,Context context) throws IOException, InterruptedException {  
  50.             String valueString;  
  51.             String out = "";  
  52.               
  53.             for(Text value : values) {  
  54.                 valueString = value.toString();  
  55.                 out += valueString+",";  
  56.             }  
  57.               
  58.             context.write(key, new Text(out));  
  59.         }  
  60.     }  
  61.   
  62.     @Override  
  63.     public int run(String[] args) throws Exception {  
  64.         Configuration conf =getConf();  
  65.           
  66.         Job job = new Job(conf,"Test_2");    //任务名:主类的名字  
  67.         job.setJarByClass(Test_2.class);        //指定class  
  68.           
  69.         FileInputFormat.addInputPath(job, new Path(args[0]));   //指定输入路径  
  70.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  //指定输出路径  
  71.           
  72.         job.setMapperClass(Map.class);    //调用上面的Map类作为Map任务代码  
  73.         job.setReducerClass(Reduce.class);   //调用上面的Reduce类做为Reduce任务代码  
  74.           
  75.         job.setOutputFormatClass(TextOutputFormat.class);  
  76.           
  77.         job.setOutputKeyClass(Text.class);    //指定输出的key的格式  
  78.         job.setOutputValueClass(Text.class);    //指定输出的value的格式  
  79.           
  80.         job.waitForCompletion(true);  
  81.           
  82.         return job.isSuccessful()?1:0;  
  83.     }  
  84.       
  85.     public static void main(String[] args) throws Exception {  
  86.         //main 方法运行  
  87.         int res = ToolRunner.run(new Configuration(),new Test_2(),args);  
  88.         System.exit(res);  
  89.     }  
  90.       
  91. }  

  

 

    传好数据,

   

 

做好配置:在项目上右键,选择Run as 下面的 Run connfigruations,前面的Main填上项目的名字,然后填上主类的名字,接下来的Arguments写上linux下面hdfs中存放文件的路径和输出结果的路径,最后点击Apply 然后点击run



 

运行结果 :刷新右边DFS Locations 下面的root目录,下面就出现了你在上一步Arguments处填写的输出目录,需要注意的是运行前要保证 root目录下面的没有和你在Argments填写时同名的输出结果的目录,



 
 双击我们的输出目录下面的part-r-00000,就可以看到我们想要的结果了:



 

 

细心的数一下,我们的数据是不是少了一条,原因是我们给的数据上面的格式不对,仔细看上面的的第二条数据,可以知道中间不是只空了一个空格,所以这一条数据就被跳过了。

 

 

心得:写完第一个Map/Reduce函数,之前也看过几个,感觉模式基本上是一样的,需要记得的就是Map函数的输出结果是Reduce函数的输入,因此在写Map方法和Reduce方法的时候就要注意里面的参数的类型要保持一致,否则会出错,其他的 就基本上按照套路来就可以了,按照不同的需求写 出不同的方法,模板就感觉只有一个。



0 0
原创粉丝点击