大数据学习笔记-2020-09-12--Hadoop-MapReduce入门与基础的wordCountJava代码实现

MapReduce

MR简介

​ MR是一个分布式运算程序的编程框架,是用户开发基于Hadoop的数据分析应用的核心框架。

​ MR的核心功能是将用户编写的业务代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。

MR优点
  • MR易于编程:写过的都懂

  • 良好的扩展性:当计算资源得不到满足时,可以简单的通过增加机器拓展其计算能力

  • 高容错性:当集群中一台机器挂了,它会将上面的计算任务转移到另一个节点上运行,不至于导致任务失败,且这个过程由Hadoop内部完成,不需要人工参与。

  • 适合PB级以上的海量数据的离线处理

MR缺点
  • 不擅长实时运算
  • 不擅长流式运算
  • 不擅长有向图运算
    • 如果多个应用程序前后存在依赖关系,前者的输出为后者的输入。在这种情况下MR完成每一个阶段的结果都会写入磁盘,会造成大量IO,性能非常低下。

MR的核心思想:

以wordCount为例

需求:统计每一个单词出现的总次数,且结果中a-p,q-z分为两个文件

  1. 分布式的运算一般分成两个阶段:map阶段和reduce阶段
  2. map阶段的MapTask并发实例完全并发运行、互不相干
  3. reduce阶段的reduceTask并发实例且互不相干,但是他们的数据依赖于上一个阶段所有的MapTask并发实例的输出
  4. MapReduce编程模型只能包含一个map阶段和一个reduce阶段
MapReduce的两个运行阶段(map和reduce)

在这里插入图片描述

  1. 输入文件安装切块大小按文件切片(split),每一片对应一个MapTask

  2. MapTask读取自身对应的文件切片后,运行map代码,对数据进行处理,然后按分区溢写到磁盘

    • 在WC中就是将数据按空格切割,然后拆分成<单词,1>这样的键值对输出
  3. reduceTask的个数取决于分区的个数,每个分区对应一个reduceTask,map阶段完成后由reduceTask获取每一个mapTask中对应分区中的数据,进行数据合并,然后输出到目标文件中

    • 在WC中就是将每一个单词对应的所有k、v对进行合并

在这里插入图片描述

MapReduce进程
  • MRAppMaster:负责整个程序过程的过程调度以及状态协调
  • mapTask:负责map阶段的整个数据处理流程
  • reduceTask:负责reduce阶段的整个数据处理流程
MapReduce编程规范

用户自己编写的程序由三个部分:Mapper、Reducer、Driver

  • mapper阶段中
    • 用户自定义的mapper要继承mapper父类方法
    • mapper输入和输出数据都是键值对
    • 业务逻辑写在map方法中
    • map方法对每个kv对调用一次
  • reducer阶段中
    • 用户自定义的reducer要继承自己的父类
    • reducer输入类型对应mapper的输出类型,也是键值对
    • reudcer的输出也是键值对
    • reudcer的业务逻辑写在reduce方法中
    • reduce方法对每组建相同的键值对掉哦那个一次
  • driver阶段
    • 相当于yarn集群的客户端,用于提交整个程序到yarn集群,提交的是封装了mr程序及相关参数的job对象

wordCount案例实操

  • 一、准备工作:

    我的输入文件为:e:/work/test/input/inputfile.txt

    内容为:

    leimiliya sikaleite meimei
    weiyan weiyan weiyan
    meimei jiejie xiaoye
    leimiliya leimiliya
    

    预期输出为:

    jiejie	1
    leimiliya	3
    meimei	2
    sikaleite	1
    weiyan	3
    xiaoye	1
    
  • 需求分析:

    1. mapper中出入的k为偏移量,v为文件中一行的内容

    2. 将v切割,每个单词都打包成输出的key,value为1

    3. reduce阶段汇总map输出的数据

    4. diver配置各类信息

  • 环境准备:

    1. 创建maven工程

    2. 配置pom.xml:

      <dependencies>
      		<dependency>
      			<groupId>junit</groupId>
      			<artifactId>junit</artifactId>
      			<version>RELEASE</version>
      		</dependency>
      		<dependency>
      			<groupId>org.apache.logging.log4j</groupId>
      			<artifactId>log4j-core</artifactId>
      			<version>2.8.2</version>
      		</dependency>
      		<dependency>
      			<groupId>org.apache.hadoop</groupId>
      			<artifactId>hadoop-common</artifactId>
      			<version>2.7.2</version>
      		</dependency>
      		<dependency>
      			<groupId>org.apache.hadoop</groupId>
      			<artifactId>hadoop-client</artifactId>
      			<version>2.7.2</version>
      		</dependency>
      		<dependency>
      			<groupId>org.apache.hadoop</groupId>
      			<artifactId>hadoop-hdfs</artifactId>
      			<version>2.7.2</version>
      		</dependency>
      </dependencies>
      
    3. 创建log4j文件并在其中写入:

      log4j.rootLogger=INFO, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
      log4j.appender.logfile=org.apache.log4j.FileAppender
      log4j.appender.logfile.File=target/spring.log
      log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
      log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
      
  • Mapper代码编写:

    /**
     * 继承hadoop提供的Mapper方法
     * 其中泛型依次对应着输入k-v类型&输出k-v类型
     */
    public class WCMapper extends
            Mapper<LongWritable, Text, Text, IntWritable> {
        //输出的键
        private Text k_out = new Text();
        //输出的值
        private IntWritable v_out = new IntWritable(1);
        /**
         * 重载父类中的map方法,父类中map方法为直接写出输入的k-v
         * @param key 输入的键,此处为文件指针的偏移量
         * @param value 输入的值,此处为一行数据
         * @param context 上下文
         */
        @Override
        protected void map(
                LongWritable key, Text value,
                    Context context) throws
                        IOException, InterruptedException {
            //按空格切割数据,得到一行中的每一个单词
            String[] words = value.toString().split(" ");
            for (String word : words) {
                //封装输出的key
                k_out.set(word);
                //写出
                context.write(k_out,v_out);
            }
        }
    }
    
  • Reducer代码编写:

    /**
    * 继承hadoop提供的Reducer父类
     * 其中泛型对应着输入的k-v与输出的k-v的类型
     */
    public class WCReducer extends
            Reducer<Text, IntWritable, Text, IntWritable> {
        //输出的值
        private IntWritable v_out = new IntWritable();
        /**
         * 重载父类中的reduce方法,父类中的reudce方法为直接写出每一个键值对
         * @param key map方法中输入的键
         * @param values map方法中输出的所有对应改键的值的迭代器
         * @param context 上下文
         */
        @Override
        protected void reduce(
                Text key, Iterable<IntWritable> values,
                    Context context) throws
                        IOException, InterruptedException {
            //计数器
            int count = 0;
            for (IntWritable value : values) {
                //累加即可
                count++;
            }
            //封装
            v_out.set(count);
            //写出
            context.write(key,v_out);
        }
    }
    
  • Driver代码编写:

    /**
     * 此类直接写main方法封装一些必要的信息到job中并提交即可
     */
    public class WCDriver {
        public static void main(String[] args)
                throws IOException, ClassNotFoundException, InterruptedException {
            //设置输入输出路径
            Path inputPath = new Path(
                    "E:/work/test/input/inputfile.txt");
            Path outputPath = new Path(
                    "E:/work/test/output");
    
            //如果输出路径已经存在会抛出异常,
            //所以判断输出路径是否存在,如果存在则将其删除
            FileSystem fs = FileSystem.get(new Configuration());
            if (fs.exists(outputPath)){
                fs.delete(outputPath,true);
            }
    
            //创建job
            Job job = Job.getInstance();
    
            //设置job
            //设置要运行的mapper和reducer类
            job.setMapperClass(WCMapper.class);
            job.setReducerClass(WCReducer.class);
    
            //设置mapper和reducer的输出k-v类型,
            // 如果两者一致,直接设置最终输出类型即可
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(IntWritable.class);
    
            //设置输入目录和输出目录
            FileInputFormat.setInputPaths(job,inputPath);
            FileOutputFormat.setOutputPath(job, outputPath);
            
            //开启并等待任务执行完成
            boolean result = job.waitForCompletion(true);
            System.out.println(result?1:-1);
    
        }
    }
    
  • 运行结果
    可以在输出的日志最后看到输出了1,代表顺利运行结束了
    找到输出文件,符合预期:
    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值