• Hadoop 新生报道(四) WordCount


         WordCount是hadoop里hello word级的第一个程序,作为一个萌新,我也来跑一跑这个,附带针对新人的说明。
         所谓WordCount,就是统计一个或几个文档中相同的单词各有多少个。
         首先要有关于MapReduce的基础,用我自己通俗的话来说一下,MapReduce是一个用来计算大型数据的分布式计算框架,所谓框架,就是定义好了样子,我们只要去实现具体的类,它就可以高效的跑起来。
         MapReduce正如其名,分为两部分,一个是Map,一个是Reduce。
         输入(文件中的内容)-->Map-->Reduce-->输出(到文件中)。
         按照规定,Map的输入和Reduce的输出都是<key,value>形式的键值对,并且类型都是实现了hadoop序列化姐扣Writable的类。
         从文件中读取数据怎么变成键值对的呢,这个后边会设置,我们采用(FileInputFormat)的形式,这样,我们会从文件中得到内容,每行的内容作为value,它的偏移量作为key(key在当前是没用的)
         Mapper的代码:
    public class WCMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
        @Override
        protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, LongWritable>.Context context)
                throws IOException, InterruptedException {
                    //accept
                    String line = value.toString();
                    //split
                    String[] words = line.split(" ");
                    //loop
                    for(String w : words){
                        //send
                        context.write(new Text(w), new LongWritable(1));
                    }
        }
    }

      Mapper这里继承的时候泛型限定了4个类型<LongWritable, Text, Text, LongWritable>,分别是输入的key,value,输出的key,value的类型,LongWritable是hadoop中long的序列化类,Text是String的序列化类。

      map函数中,Mapper从文档中得到偏移量(本程序不用,不管他)在key中,每行的值在value中,然后从value中用空格分开得到每个词,然后现在得到的每个词都是一次的,所以给content中添加<单词,1>,保存在content中,传给reduce。

      Reduce的代码:

    public class WCReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
        @Override
        protected void reduce(Text key, Iterable<LongWritable> values,
                Reducer<Text, LongWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
            // TODO Auto-generated method stub
                    //define a counter
                    long counter = 0;
                    //loop
                    for(LongWritable l : values){
                        counter += l.get();
                    }
                    //write
                    context.write(key, new LongWritable(counter));
        }
    }

      Reduce继承的时候,限定的<Text, LongWritable, Text, LongWritable>是输入的<key,value>和输出的<key,value>,输入必须和Mapper的输出一样,输出自己定义,我们定义的是输出单词和它的次数。

      Mapper的输出传到Reduce的时候,中间会有一个过程(框架自动干的活,这就是框架的好处了),他会把Mapper输出的键值对中key相同的键值对合并,比如<hadoop,1>和<hadoop,1>会因为key都是hadoop二合并变成<hadoop,[1,1]>,如果再有一个<hadoop,1>,就会合并成<hadoop,[1,1,1]>。

      所以在reduce函数中,对每一个key对应的value迭代,每次得到一个次数(我们都设定的1),累加起来就是这个单词的次数了。

       然后,每个MapReduce程序都是一个job,需要开启。

      运行类(都有注释就不解释了):

      

    public class WCRun {
        public static void main(String[] args) {
            try {
                //下边4行代码设置job的基础信息,setJarByClass就是设置当前运行的main所在的class文件
                Configuration conf = new Configuration();  
                Job job =Job.getInstance(conf);
                job.setJarByClass(WCRun.class);  
                job.setJobName("wordcount");  
          
                //设置Mapper和Reduce的class文件是哪个
                job.setMapperClass(WCMapper.class);  
                job.setReducerClass(WCReducer.class);  
                
                //设置输出的key和value的类型
                job.setOutputKeyClass(Text.class);  
                job.setOutputValueClass(LongWritable.class);  
          
                //设置输入也就是从文件中得到键值对的方法,也就是我们之所以得到的是偏移量和一行文本,就是这个决定的
                job.setInputFormatClass(TextInputFormat.class);  
                //设置输出的格式,同输入,不过内容是我们自己定义的
                job.setOutputFormatClass(TextOutputFormat.class);  
                //得到输入路径和输出路径,这里用参数,注意输出目录不能存在
                FileInputFormat.addInputPath(job, new Path(args[0]));
                FileOutputFormat.setOutputPath(job, new Path(args[1]));  
                //启动job并等待运行结果
                 job.waitForCompletion(true);  
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }

      !!!再次提醒,输出目录不能存在!!!

      运行的话,可以配置本地模式,可以集群运行,我们用集群跑一跑。

      首先吧整个程序打包成jar包,项目-->export-->java,jar

      然后把jar文件上传到我们的集群上。

      在hdfs里建一个输入文件夹,找一个文档放进去,输出的目录一定不要建(重要的事说三遍)。

      

      然后运行, 指令是 hadoop jar 你的程序的jar包 程序的main在的类 输入文件夹 输出文件夹

      

      程序运行成功,进入wcout看一看

      

      有两个文件,第一个表示我们成功了,第二个就是结果文件,吧第二个文件get到本地打开看一看

      

      统计的结果,大功告成。

      ps:都是学hadoop的新手,欢迎评论留言交流,一起进步。

  • 相关阅读:
    使用存储过程查询并按每页10条记录分页显示图书借阅纪录
    两个div并排 左边div宽固定 右边自适应
    java比较时间及时间的转换
    java使用commons.io的FileUtils进行文件拷贝
    实现image宽度100%,高度与宽度一致
    vue请求前的loading动画效果
    vue项目加载前空白的动画过渡效果
    element-ui和semantic-ui冲突的解决方法--局部引入semantic-ui的css
    vue使用formdata上传多个图片,springboot以文件数组的形式接受
    快速创建vuepress项目(使用vuepress写文档)
  • 原文地址:https://www.cnblogs.com/alexfly/p/7308684.html
Copyright © 2020-2023  润新知