MapReduce WordCount代码和编码规范详细说明

1.WordCount代码

自带的wordCount程序执行
本地执行
hadoop jar hadoop-mapreduce-examples-2.7.5.jar wordcount /wc/input1/ /wc/output1/

查看结果
hadoop fs -cat /wc/output1/part-r-00000
wordCount代码如下:
package com.ghgj.mapreduce.wc.demo;
import java.io.IOException;
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;
/**
 *
 * 描述: MapReduce出入门:WordCount例子程序
 */
public class WordCountMR {
    /**
     * 该main方法是该mapreduce程序运行的入口,其中用一个Job类对象来管理程序运行时所需要的很多参数:
     * 比如,指定用哪个组件作为数据读取器、数据结果输出器 指定用哪个类作为map阶段的业务逻辑类,哪个类作为reduce阶段的业务逻辑类
     * 指定wordcount job程序的jar包所在路径 .... 以及其他各种需要的参数
     */
    public static void main(String[] args) throws Exception {
        // 指定hdfs相关的参数
        Configuration conf = new Configuration();
//         conf.set("fs.defaultFS", "hdfs://hadoop02:9000");
        System.setProperty("HADOOP_USER_NAME", "hadoop");
        // 这是高可用的集群的配置文件。如果不是高可用集群,请自行替换配置文件
//        conf.addResource("hdfs_config/core-site.xml");
//        conf.addResource("hdfs_config/hdfs-site.xml");
        // conf.set("mapreduce.framework.name", "yarn");
        // conf.set("yarn.resourcemanager.hostname", "hadoop04");
        // 通过Configuration对象获取Job对象,该job对象会组织所有的该MapReduce程序所有的各种组件
        Job job = Job.getInstance(conf);
        // 设置jar包所在路径
        job.setJarByClass(WordCountMR.class);
        // 指定mapper类和reducer类
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        // Mapper的输入key-value类型,由MapReduce框架决定
        // 指定maptask的输出类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        // 假如 mapTask的输出key-value类型,跟reduceTask的输出key-value类型一致,那么,以上两句代码可以不用设置
        // reduceTask的输入key-value类型 就是 mapTask的输出key-value类型。所以不需要指定
        // 指定reducetask的输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);
        // 为job指定输入数据的组件和输出数据的组件,以下两个参数是默认的,所以不指定也是OK的
        // job.setInputFormatClass(TextInputFormat.class);
        // job.setOutputFormatClass(TextOutputFormat.class);
        // 为该mapreduce程序制定默认的数据分区组件。默认是 HashPartitioner.class
        // job.setPartitionerClass(HashPartitioner.class);
        // 如果MapReduce程序在Eclipse中,运行,也可以读取Windows系统本地的文件系统中的数据
         Path inputPath = new Path("D:\\bigdata\\wordcount\\input");
         Path outputPath = new Path("D:\\bigdata\\wordcount\\output33");
        // 设置该MapReduce程序的ReduceTask的个数
        // job.setNumReduceTasks(3);
        // 指定该mapreduce程序数据的输入和输出路径
//        Path inputPath = new Path("/wordcount/input");
//        Path outputPath = new Path("/wordcount/output");
        // 该段代码是用来判断输出路径存在不存在,存在就删除,虽然方便操作,但请谨慎
        FileSystem fs = FileSystem.get(conf);
        if (fs.exists(outputPath)) {
            fs.delete(outputPath, true);
        }
        // 设置wordcount程序的输入路径
        FileInputFormat.setInputPaths(job, inputPath);
        // 设置wordcount程序的输出路径
        FileOutputFormat.setOutputPath(job, outputPath);
        // job.submit();
        // 最后提交任务(verbose布尔值 决定要不要将运行进度信息输出给用户)
        boolean waitForCompletion = job.waitForCompletion(true);
        System.exit(waitForCompletion ? 0 : 1);
    }
    /**
     * Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
     *
     * KEYIN 是指框架读取到的数据的key的类型,在默认的InputFormat下,读到的key是一行文本的起始偏移量,所以key的类型是Long
     * VALUEIN 是指框架读取到的数据的value的类型,在默认的InputFormat下,读到的value是一行文本的内容,所以value的类型是String
     * KEYOUT 是指用户自定义逻辑方法返回的数据中key的类型,由用户业务逻辑决定,在此wordcount程序中,我们输出的key是单词,所以是String
     * VALUEOUT 是指用户自定义逻辑方法返回的数据中value的类型,由用户业务逻辑决定,在此wordcount程序中,我们输出的value是单词的数量,所以是Integer
     *
     * 但是,String ,Long等jdk中自带的数据类型,在序列化时,效率比较低,hadoop为了提高序列化效率,自定义了一套序列化框架
     * 所以,在hadoop的程序中,如果该数据需要进行序列化(写磁盘,或者网络传输),就一定要用实现了hadoop序列化框架的数据类型
     *
     * Long ----> LongWritable
     * String ----> Text
     * Integer ----> IntWritable
     * Null ----> NullWritable
     */
    static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
        /**
         * LongWritable key : 该key就是value该行文本的在文件当中的起始偏移量
         * Text value : 就是MapReduce框架默认的数据读取组件TextInputFormat读取文件当中的一行文本
         */
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            // 切分单词
            String[] words = value.toString().split(" ");
            for (String word : words) {
                // 每个单词计数一次,也就是把单词组织成<hello,1>这样的key-value对往外写出
                context.write(new Text(word), new IntWritable(1));
            }
        }
    }
    /**
     * 首先,和前面一样,Reducer类也有输入和输出,输入就是Map阶段的处理结果,输出就是Reduce最后的输出
     * reducetask在调我们写的reduce方法,reducetask应该收到了前一阶段(map阶段)中所有maptask输出的数据中的一部分
     * (数据的key.hashcode%reducetask数==本reductask号),所以reducetaks的输入类型必须和maptask的输出类型一样
     *
     * reducetask将这些收到kv数据拿来处理时,是这样调用我们的reduce方法的: 先将自己收到的所有的kv对按照k分组(根据k是否相同)
     * 将某一组kv中的第一个kv中的k传给reduce方法的key变量,把这一组kv中所有的v用一个迭代器传给reduce方法的变量values
     */
    static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
        /**
         * Text key : mapTask输出的key值
         * Iterable<IntWritable> values : key对应的value的集合(该key只是相同的一个key)
         *
         * reduce方法接收key值相同的一组key-value进行汇总计算
         */
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            // 结果汇总
            int sum = 0;
            for (IntWritable v : values) {
                sum += v.get();
            }
            // 汇总的结果往外输出
            context.write(key, new IntWritable(sum));
        }
    }
}
总结:
  • 程序有个main方法,job对象存储了信息。指定Mapper类和Reducer类
  • TokenizerMapper 类继承了 Mapper 类
  • IntSumReducer 类继承了 Reducer 类
 

2.编码规范

  • 编写的程序分为三个部分:Mapper,Reducer,Driver(提交运行MR程序的客户端)
  • Mapper的输入和输出数据是key-value(键值)对的形式(类型可以自定义)
  • Mapper中的业务逻辑写在map()方法中
  • map()方法(maptask 进程)对每一个<k,v>调用一次
  • Reducer 的输入数据类型对应 Mapper 的输出数据类型
  • Reducer 的业务逻辑写在 reduce()方法中
  • Reducetask 进程对每一组相同 k 的<k,v>组调用一次 reduce()方法
  • 整个程序需要一个 Drvier 来进行提交,提交的是一个描述了各种必要信息的 job 对象
 

3.WordCount原理

(1)map阶段
maptask处理每个数据分块,读取一行,根据分隔符把单词转换成一个key-value对,比如单词 hello,就转换成<’hello’,1>发送给 reducetask 去汇总
(2)reduce阶段
reducetask 阶段将接受 maptask 的结果,来做汇总计数
 

4.运行方式

  • 首先要把代码打成 jar 上传到 linux 服务器
  • 用 hadoop jar 的命令去提交代码到 yarn 集群运行
  • 处理的数据和输出结果应该位于 hdfs 文件系统
 

5.常用数据类型

 
ByteWritable:    单字节数值
IntWritable:    整型数
LongWritable:    长整型数
FloatWritable:    浮点数
DoubleWritable:    双字节数值
BooleanWritable:    标准布尔型数值        
Text:    使用UTF8格式存储的文本
NullWritable:    当<key,value>中的key或value为空时使用
ImmutableBytesWritable  不可变字节类型

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值