MapReduce入门

MapReduce入门

一、回顾

  1. HDFS架构

    • 分布式
      • 普通主从架构
        • 主:管理
        • 从:执行
      • 公平架构
        • 每个节点都是公平节点
        • Zookeeper
    • 本质:将多台机器的文件系统从逻辑上合并为一个整体
    • 节点
      • NameNode:主:管理
        • 管理集群:DataNode
        • 管理接客
        • 管理元数据
      • DataNode:从:存储
        • 每个DataNode负责管理自己所在节点的文件系统
        • 负责接收NameNode的读写任务分配:数据写入DataNode所在的Linux文件系统的
        • dfs.datanode.data.dir:决定了DataNode将数据存储在Linux的什么位置
      • 元数据:记录了数据文件被拆分的每个部分【数据块】的存储信息
        • 产生:格式化fsiamge
        • 存在
          • 磁盘:fsiamge
            • dfs.namenode.name.dir
          • 内存:NameNode每次会加载到内存
            • NameNode每次读写内存元数据,只有内存元数据在发生变化
          • 问题:如果NameNode故障,内存元数据丢失,重新加载本地,但是不一致?
            • NameNode会将所有内存元数据的变化写入edits文件
              • dfs.namenode.edits.dir
            • 解决:每次NameNode启动将edits与fsiamge文件进行合并加载到内存
          • 问题:edits文件越来越大,有很多过期的元数据,导致每次NameNode启动会很慢?
          • 解决:SecondaryNameNode
            • 功能:定期或者定量将edits文件与fsiamge文件合并生成新的fsimage文件
            • 目的:减小edits文件的数据量,提高NameNode的合并速度
  2. JavaAPI

    • 如何构建连接

      //用于管理Hadoop程序所有配置信息
      Configuration conf = new Configuration();
      conf.set("fs.defaultFS","hdfs://node1:8020")
      FileSyste hdfs = FileSystem.get(conf);
      
    • 常用方法

      • mkdir
      • delete
      • exsits
      • create
      • open
  3. Hadoop HA

    • 问题:主节点单点故障

    • 解决:Hadoop提供了HA方案,启动两个主节点

    • 问题1:两个NameNode,谁工作,谁不工作的?

      • 选举:利用zookeeper的临时节点和监听机制来实现辅助选举
      • 原理
        • 两个NameNode都到Zookeeper创建同一个临时节点,谁创建成功,谁就是Active
        • Standby的NameNode会对这个临时节点设置监听,如果临时节点消失,表示ActiveNameNode故障
        • Standby会创建临时节点,成为Active状态
      • 实现:ZKFC
        • 功能一:负责监听NameNode以及实现切换
        • 功能二:负责帮NameNode连接Zookeeper

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-REtf0bDW-1615044933716)(Day06_MapReduce入门.assets/image-20201030095511604.png)]

    • 问题2:NameNode功能的问题

      • 管理集群
        • 所有DataNode会向所有NameNode注册并且发送报告
      • 接客
        • 客户端挨个请求,最终请求提交给Active的NameNode
      • 管理元数据:如何保证两个NameNode的元数据是一致的
        • 解决:共享edits文件
          • Active:元数据变化写入edits
          • Standby:读edits对自己元数据修改即可
        • Journalnode:非常类似于Zookeeper
          • 功能:共享存储edits
          • 区别:没有文件大小的存储限制
          • 理解:这是一种特殊的Zookeeper的集群
    • HA架构中没有SecondaryNameNode

      • StandBy的NameNode接替了SecondaryNameNode的功能
      • 将读取的edits与自己的fsiamge定期合并,生成新的fsiamge,将新的fsimage发给Active一份
  • 问题

    • 脑裂问题:同时出现了两个Active的NameNode

      • 正常情况

        • A和B
        • 第一次:A的ZKFC1创建临时节点file1,创建成功,A就是Active
          • B是Standby,B的ZKFC2要监听这个临时节点file1
        • 第二次
          • 如果A故障,ZKFC1发现A故障,主动删除file1,file1消失
          • zkfc2收到监听的通知,知道file1被删除,zkfc2创建了file1
          • B成了为Active状态
      • 特殊情况

        • A和B

        • 第一次:A的ZKFC1创建临时节点file1,创建成功,A就是Active

          • B是Standby,B的ZKFC2要监听这个临时节点file1
        • 第二次

          • 如果zkfc1故障,连接断开,file1被自动删除
          • 如果file1消失,zkfc2收到监听的通知,知道file1被删除,zkfc2创建了file1
          • B成了为Active状态,A依旧是Active
          • 出现了两个Active的状态
        • 解决

          image-20201030102424571

          • A和B
          • 第一次:A的ZKFC1创建临时节点file1,创建成功,A就是Active
            • ZKFC1创建永久性节点file2
            • B是Standby,B的ZKFC2要监听这个临时节点file1
          • 第二次
            • 如果zkfc1故障,连接断开,file1被自动删除
            • 如果file1消失,zkfc2收到监听的通知,知道file1被删除,zkfc2创建了file1
            • B成了为Active状态,A依旧是Active
            • ZKFC2同时会发现file2已存在,说明是zkfc1故障了,说明A还是Active状态
            • ZKFC2会通过隔离机制到A所在的节点上,强转切换为Standby,如果切换不成功,强制kill掉A
    • 客户端配置

      • HA模式下,如果自己写代码,代码中怎么配置服务端地址?
      • 方式一:将core-site.xml和hdfs-site.xml放入resources目录中
      • 方式二:将core-site.xml和hdfs-site.xml中所有的属性在conf中设置
      • 以后只要是HA模式,任何一种客户端要访问HDFS,都必须获取这两个配置文件
    • 反馈

      • 建议下课期间问上课记录的问题
      • ZK架构及存储的数据
        • ZK会存储哪些数据?
          • 由我们自己决定
        • ZK架构:公平节点
          • 主节点和从节点存储的数据是一致的
          • 主节点和从节点都能接受客户端请求
          • 从节点有资格被选举为主节点的
          • 区别:只有主节点能实现写入操作
      • 配置
        • xxx-env.sh:修改环境变量的
          • hadoop-env
          • mapred-env
          • yarn-env
          • ||
          • JDK路径
        • xxx-site.xml:配置属性
          • core-site.xml:用于自定义Hadoop全局配置
            • core-default.xml
            • fs.defaultFS
            • hadoop.tmp.dir
          • hdfs-site.xml:用于自定义HDFS属性配置
            • hdfs-default.xml
          • mapred-site.xml:用于自定义MapReduce属性配置
            • mapred-default. xml
          • yarn-site.xml:自定义YARN属性的配置
            • yarn-default.xml
        • slaves:用于配置从节点的地址的
          • DataNode
          • NodeManager
          • NameNode地址:core-site
          • ResourceManager:yarn-site:yarn.resourcemanager.hostname
          • 问题:为什么一台机器既是DataNode也是NodeManager?
            • 优先本地计算
        • Hadoop中如何管理配置?
          • Congratulation:用于管理Hadoop所有属性配置
          • step1:加载default文件,所有默认配置
          • step2:加载site文件,用用户自定义配置覆盖默认配置
      • 熟练度
        • 理论:猜别人是怎么想的,思考为什么这么设计
          • 问,背
        • 操作:死的
          • 通过操作来验证理论
          • 命令、API
          • 多练习
          • 当天自己能写出来就可以,休息那天,多敲几遍

二、课程目标

  1. MapReduce的功能以及应用场景
  2. 基本理论【重要】
    • MapReduce如何实现数据分布式处理:五大阶段【核心】
    • MapReduce编程规则
  3. 开发案例【掌握基本开发】
    • WordCount
    • 二手房的统计分析

三、MapReudce编程模型

1、功能

  • 分布式计算
    • step1:先开发一个分布式【多进程】程序
    • step2:需要一个分布式资源环境
    • 只有分布式程序放在分布式的资源环境中运行:分布式计算
  • MapReduce:就是一套分布式编程的API
    • 只要基于MapReduce的API进行编程,就可以直接开发出一个分布式程序
    • MapReduce底层会自动将任务逻辑进行拆分成多个小的任务
    • 需求:1 + ……+9
    • 拆分:逻辑上拆分了进程
      • Task1:1+2+3
      • Task2:4+5+6
      • Task3:7+8+9
      • Task4:6+15+24 = 45
    • YARN:提供分布式资源环境,分布式资源管理和任务调度平台
      • node1:Task1
      • node2:Task2
      • node3:Task3 Task4

2、思想和应用场景

  • 设计:分布式编程模型

    • 分而治之
    • step1:将一个大的计算任务拆分成多个小的计算任务
    • step2:将每个小的计算任务交给不同的机器来并行执行
    • step3:将每个小任务的结果进行合并
  • 应用

    • 设计:让分布式计算应用于廉价的机器上:配置比较低的机器

      • 使用了大量的磁盘机制
    • 离线分布式大数据计算

    • 不适合处理小数据

3、阶段:基本原理

  • 正常一个计算处理数据的程序的步骤

    • step1:读取输入数据
    • step2:处理输出数据
    • step3:输出处理结果
  • MapReduce的阶段划分

    • Map阶段
    • Reduce阶段
  • MapReduce的五大阶段

    • Input:负责整个程序的输入

      • 功能:根据代码中定义的输入,读取对应的数据内容

        • 功能一:将读取到的数据根据分的规则,划分为多个分片:Split

          • 类似于:1到9有9个数字
            • 将1到9的9个数字划分为3个部分
        • 功能二:将每个Split中的每一条数据变成一个KV对

          • K1
          • V1
          a		1
          a		2
          a		3
          a		4
          a		5
          a		6
          a		7
          a		8
          a		9
          
    • Map:负责任务的划分的

      • 功能:根据Input阶段划分的Split来划分MapTask任务进程

        • 一个Split = 一个MapTask进程

        • 任务的划分

          • MapTask1

            a		1
            a		2
            a		3
            
          • MapTask2

            a		4
            a		5
            a		6
            
          • MapTask3

            a		7
            a		8
            a		9
            
      • 处理:每个MapTask会调用Map类的map方法来对自己负责的每一条数据处理一次

        • map方法处理的逻辑:由用户自定义

          public void map (K1,V1){
          	由用户自己决定
          }
          
      • 输出:

        • K2
        • V2
    • Shuffle:分组和排序

      • 分组:按照K2进行分组
        • 相同K2的V2会放入同一个迭代器中
    • 排序:按照K2进行排序

      • 目的:加快分组
    • 输出

      • K2 Iter<K2对应的所有V2>
    • Reduce:将Map输出的所有数据在分组排序以后进行聚合,默认只会启动一个ReduceTask

      • 聚合逻辑:ReduceTask会调用reduce方法进行聚合

        public void reduce(K2,iter){
        	由用户自定义
        }
        
    • 输出

      • K3
        • V3
    • Output:负责整个程序的输出,将结果进行保存

      • 将K3,V3根据输出的方法进行保存

4、词频统计的分析

  • Input

    • 输入

      hadoop hive hbase
      hadoop hive
      spark hbase hadoop
      
    • 功能

      • 将数据切分
      • 将每一条数据转换为一个KV
        • 由输入的类决定:TextInputFormat,默认的输入类
        • K1:行的偏移量:这个东西没用
        • V1:行的内容
    • 输出

      K1				V1
      0				hadoop hive hbase
      23				hadoop hive
      32				spark hbase hadoop
      
  • Map

    • 处理:每一个K1V1调用一次map方法

    • map方法

      public void map(K1,V1){
      	String[] words = v1.split(" ");
      	for(String word : words){
      			K2:word
      			V2:1
      	}
      }
      
    • 输出

      • K2:单词
      • V2:1
      K2			V2
      hadoop		1
      hive		1
      hbase		1
      hadoop		1
      hive		1
      spark		1
      hbase		1
      hadoop		1
      
  • Shuffle

    • 排序:按照K2排序

    • 分组:按照K2分组,相同K2对应的V2放入同一个迭代器

    • 输出

      hadoop		<1,1,1>
      hbase		<1,1>
      hive		<1,1>
      spark		<1>
      
  • Reduce

    • 处理:每一组数据【每一种K2】调用一次reduce方法

    • reduce方法

      public void reduce(K2,iter:values){
      	for(value:values){
      		sum += value
      	}
      	K3:K2
      	V3:sum
      }
      
    • 输出

      • K3
      • V3
  • Output

    hadoop  3
    hbase   2
    hive    2
    spark   1
    

四、MapReduce编程规则

1、Driver类

  • 用于运行程序的类,包含main方法,作为程序运行的入口
  • 官方推荐:继承 Configured 实现 Tool
    • 实现run方法
  • main:作为程序的入口,负责调用run方法
  • run:构建、配置、提交运行MapReduce的Job
  • 这个类要自己写

2、Input类

  • 负责整个程序的输入,由输入类决定:InputFormat
  • 了解基本的三个子类:不同的子类用于读取不同的数据
    • TextInputFormat:用于读取文件的类,MapReduce中默认的输入类
    • DBInputFormat:用于读取MySQL数据库的数据
      • Sqoop:将MySQL数据与HDFS之间实现导入导出
    • TableInputFormat:用于读取Hbase的数据
  • TextInputFormat:默认会读取fs.defaultFS对应的文件系统中的文件
    • 将文件拆分为分片
    • 将文件中的每一行变成一个KV
      • K1:行的偏移量
      • V1:行的内容
  • 这个类不用自己写

3、Mapper类

  • 在Map阶段,每一个MapTask会构建一个Mapper类的实例
  • Mapper类会包含map方法,MapTask会对每一条K1V1调用一次map方法
  • map方法的处理逻辑:由用户自定义
  • 规则:继承Mapper,重写map方法

4、Reducer类

  • 在Reduce阶段,每一个ReduceTask会构建一个Reducer类实例,调用reduce方法
  • Reduce类包含reduce方法
  • reduce方法的处理逻辑:由用户自定义
  • 规则:继承Reducer类,重写reduce方法

5、Output类

  • 负责整个程序的输出,由输出类:OutputFormat
  • 了解常见的输出类
    • TextOutputFormat:默认将结果保存到文件中,MapReduce默认的输出类
    • DBOutputFormat:用于将结果保存到MySQL数据库中
    • TableOutputFormat:将结果保存到Hbase中
  • TextOutputFormat:将Reduce的结果K3,V3保存到文件系统中
    • K3与V3之间使用制表符分隔
  • 这个不用自己写

6、数据结构

  • 整个MapReduce在处理数据的时候,所有的数据都是以KV形式存在的

7、数据类型

  • 所有的分布式中:Hadoop中必须使用支持序列化的数据类型
  • Java中常用类型:String,int,long,double
    • 不支持序列化
  • MapReduce中提供了对应的支持序列化类型
    • Text(字符串类型)
    • IntWritable
    • LongWritable
    • DoubleWritable
    • BooleanWritable
    • NullWritable

五、MapReduce编程模板

1、Driver

package bigdata.itcast.cn.hadoop.mapreduce.mode;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

/**
 * @ClassName MapReduceDriver
 * @Description TODO Mapreduce模板的Driver
 *          规则:继承Configured 实现 Tool
 *          方法:
 *              main:作为程序运行的入口,调用run方法
 *              run:构建、配置、提交运行一个Mapreduce的Job
 * @Date 2020/10/30 15:34
 * @Create By     Frank
 */
public class MapReduceDriver extends Configured implements Tool {

    /**
     * 构建job
     * 配置Job:读哪个文件,将结果保存到什么地方去呀;
     * 提交Job
     * @param args
     * @return
     * @throws Exception
     */
    public int run(String[] args) throws Exception {

        /**
         * todo:1-构建一个Mapreduce的Job
         */
        Job job = Job.getInstance(this.getConf(),"mode");//加载配置,以及定义job的名称
        job.setJarByClass(MapReduceDriver.class);//指定当前类可以通过jar包运行

        /**
         * todo:2-配置Mapreduce的五大阶段
         */
        //Input
//        job.setInputFormatClass(TextInputFormat.class);//指定输入类,默认类就是TextInputFormat,如果需要更改,需要写
        //添加读取的文件路径
        Path inputPath = new Path(args[0]);//用整个程序的第一个参数来作为输入
        TextInputFormat.setInputPaths(job,inputPath);//设置输入要读取的文件路径

        //Map
        job.setMapperClass(null);//指定Mapper类
        job.setMapOutputKeyClass(null);//指定Map阶段输出的Key的类型,K2的类型
        job.setMapOutputValueClass(null);//指定Map阶段输出的Value的类型,V2的类型

        //Shuffle
//        job.setGroupingComparatorClass(null);
//        job.setSortComparatorClass(null);
//        job.setPartitionerClass(null);
//        job.setCombinerClass(null);

        //Reduce
        job.setReducerClass(null);//设置Reduce类
        job.setOutputKeyClass(null);//设置Reduce输出的Key的类型,就是K3
        job.setOutputValueClass(null);//设置Reduce输出的Value的类型,就是V3
//        job.setNumReduceTasks(1);//设置reduceTask的个数,默认为1



        //Output
//        job.setOutputFormatClass(TextOutputFormat.class);//指定输出类,默认类就是TextOutputFormat
        Path outputPath = new Path(args[1]);//用整个程序的第二个参数来作为输出
        TextOutputFormat.setOutputPath(job,outputPath);//设置输出保存结果的路径

        /**
         * todo:3-提交Mapreduce的Job,运行
         */
        //提交运行,返回boolean值,如果为true,表示运行成功了,返回false,表示运行失败了
        return job.waitForCompletion(true) ? 0 : -1;
    }

    /**
     * 作为程序入口,调用run方法
     * @param args
     */
    public static void main(String[] args) throws Exception {
        //构建一个Configuration对象;管理当前hadoop程序的配置
        Configuration conf = new Configuration();
        //通过Hadoop的工具类来调用当前类的run方法;第二个参数:非静态方法需要用对象去调用
        //如果结果返回的是0则表示运行成功
        int status = ToolRunner.run(conf, new MapReduceDriver(), args);
        //根据运行的状态退出程序
        System.exit(status);
    }
}

运行的时候可以通过args传递参数

image-20210306215117771

2、Mapper

package bigdata.itcast.cn.hadoop.mapreduce.mode;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @ClassName MapReduceMapper
 * @Description TODO Mapreduce模板的Mapper类
 *              r<KEYIN, VALUEIN, :Map输入的KV类型,K1,V1的类型
 *                  由Input决定
 *              KEYOUT, VALUEOUT>:Map输出的KV类型,K2,V2的类型
 *                  由map方法决定
 * @Date 2020/10/30 16:09
 * @Create By     Frank
 */
public class MapReduceMapper extends Mapper<LongWritable, Text,Text,Text> {

    /**
     * 每一条K1V1调用一次
     * @param key:就是K1
     * @param value:就是V1
     * @param context:上下文对象,用于实现上下文数据的传递的
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        /**
         * 处理逻辑由用户自己决定
         */
    }
}

3、Reducer

package bigdata.itcast.cn.hadoop.mapreduce.mode;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @ClassName MapReduceReducer
 * @Description TODO Mapreduce编程模板的Reducer类
 *              r<KEYIN, VALUEIN, :Reduce输入的KV类型,K2,V2的类型
 *                  由map方法决定
 *              KEYOUT, VALUEOUT>:Reduce从输出的KV类型,K3,V3的类型
 *                  由reduce方法决定
 * @Date 2020/10/30 16:13
 * @Create By     Frank
 */
public class MapReduceReducer extends Reducer<Text, Text,Text,Text> {

    /**
     * 每一组数据调用一次reduce方法
     * @param key:K2
     * @param values:相同K2对应的V2的迭代器
     * @param context:上下文对象
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        /**
         * 处理逻辑由用户自己决定
         */
    }
}

4、一个文件中定义

package bigdata.itcast.cn.hadoop.mapreduce.mode;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;

/**
 * @ClassName MapReduceDriver
 * @Description TODO Mapreduce模板,三个类在一个文件中,Map类和Reduce类必须为static修饰
 *          规则:继承Configured 实现 Tool
 *          方法:
 *              main:作为程序运行的入口,调用run方法
 *              run:构建、配置、提交运行一个Mapreduce的Job
 * @Date 2020/10/30 15:34
 * @Create By     Frank
 */
public class MapReduceMode extends Configured implements Tool {

    /**
     * 构建job
     * 配置Job
     * 提交Job
     * @param args
     * @return
     * @throws Exception
     */
    public int run(String[] args) throws Exception {

        /**
         * todo:1-构建一个Mapreduce的Job
         */
        Job job = Job.getInstance(this.getConf(),"mode");//加载配置,以及定义job的名称
        job.setJarByClass(MapReduceMode.class);//指定当前类可以通过jar包运行

        /**
         * todo:2-配置Mapreduce的五大阶段
         */
        //Input
//        job.setInputFormatClass(TextInputFormat.class);//指定输入类,默认类就是TextInputFormat,如果需要更改,需要写
        //添加读取的文件路径
        Path inputPath = new Path(args[0]);//用整个程序的第一个参数来作为输入
        TextInputFormat.setInputPaths(job,inputPath);//设置输入要读取的文件路径

        //Map
        job.setMapperClass(MrMapper.class);//指定Mapper类
        job.setMapOutputKeyClass(Text.class);//指定Map阶段输出的Key的类型,K2的类型
        job.setMapOutputValueClass(Text.class);//指定Map阶段输出的Value的类型,V2的类型

        //Shuffle
//        job.setGroupingComparatorClass(null);
//        job.setSortComparatorClass(null);
//        job.setPartitionerClass(null);
//        job.setCombinerClass(null);

        //Reduce
        job.setReducerClass(MrReduce.class);//设置Reduce类
        job.setOutputKeyClass(Text.class);//设置Reduce输出的Key的类型,就是K3
        job.setOutputValueClass(Text.class);//设置Reduce输出的Value的类型,就是V3
//        job.setNumReduceTasks(1);//设置reduceTask的个数,默认为1



        //Output
//        job.setOutputFormatClass(TextOutputFormat.class);//指定输出类,默认类就是TextOutputFormat
        Path outputPath = new Path(args[1]);//用整个程序的第二个参数来作为输出
        TextOutputFormat.setOutputPath(job,outputPath);//设置输出保存结果的路径

        /**
         * todo:3-提交Mapreduce的Job,运行
         */
        //提交运行,返回boolean值,如果为true,表示运行成功了,返回false,表示运行失败了
        return job.waitForCompletion(true) ? 0 : -1;
    }

    /**
     * 作为程序入口,调用run方法
     * @param args
     */
    public static void main(String[] args) throws Exception {
        //构建一个Configuration对象
        Configuration conf = new Configuration();
        //通过Hadoop的工具类来调用当前类的run方法
        int status = ToolRunner.run(conf, new MapReduceMode(), args);
        //根据运行的状态退出程序
        System.exit(status);
    }

    //Mapper类
    public static class MrMapper extends Mapper<LongWritable, Text,Text,Text>{
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

        }
    }

    //Reducer
    public static class MrReduce extends Reducer<Text,Text,Text,Text>{
        @Override
        protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {

        }
    }

}

六、MapReduce实现WordCount

1、需求

  • 通过自己开发wordcount程序实现词频统计

2、分析

  • 参考三.4

3、实现

package bigdata.itcast.cn.hadoop.mapreduce.wordcount;

import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;

/**
 * @ClassName WordCountMr
 * @Description TODO 自定义开发实现wordcount程序
 * @Date 2020/10/30 16:36
 * @Create By     Frank
 */
public class WordCountMr extends Configured implements Tool {

    //构建,配置,提交
    public int run(String[] args) throws Exception {
        //todo:1-构建
        Job job = Job.getInstance(this.getConf(),"userwc");
        job.setJarByClass(WordCountMr.class);
        //todo:2-配置
        //input
        Path inputPath = new Path(args[0]);
        TextInputFormat.setInputPaths(job,inputPath);
        //map
        job.setMapperClass(WcMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //reduce
        job.setReducerClass(WcReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //output
        Path outputPath = new Path(args[1]);
        TextOutputFormat.setOutputPath(job,outputPath);

        //todo:3-提交
        return job.waitForCompletion(true) ? 0:-1;
    }

    //作为程序入口,负责调用run方法
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        int status = ToolRunner.run(conf, new WordCountMr(), args);
        System.exit(status);
    }


    public static class WcMapper extends Mapper<LongWritable, Text,Text, IntWritable>{

        //定义输出的Key:单词
        Text outputKey = new Text();
        //定义输出的Value:恒为1
        IntWritable outputValue = new IntWritable(1);

        /**
         * 每一条数据会调用一次map方法
         * @param key:K1,行的偏移量
         * @param value:V1:行的内容
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            //将每一行的内容进行分割,得到每个单词
            String[] words = value.toString().split(" ");
            //遍历取出每个单词
            for (String word : words) {
                //将单词作为Key
                this.outputKey.set(word);
                //输出:write方法用于将新的KV输出到下一步
                context.write(this.outputKey,this.outputValue);
            }

        }
    }


    public static class WcReducer extends Reducer<Text, IntWritable,Text, IntWritable>{

        //定义输出的Value
        IntWritable outputValue = new IntWritable();

        /**
         * 每一组调用一次reduce方法
         * @param key:单词
         * @param values:同一个单词对应的所有value
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable value : values) {
                sum += value.get();
            }
            //将单词出现的次数赋值给value
            this.outputValue.set(sum);
            //输出
            context.write(key,this.outputValue);
        }
    }

}

4、集群运行:生产

  • 打成jar包,上传到Linux上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iK4Ndp4v-1615044933721)(Day06_MapReduce入门.assets/image-20201030170025570.png)]

  • 通过yarn运行

    yarn jar /export/data/wordcount.jar bigdata.itcast.cn.hadoop.mapreduce.wordcount.WordCountMr /wordcount/input/wordcount.txt  /wordcount/output3
    

5、本地运行

  • Mapreduce直接在本地启动一个JVM来运行代码,没有YARN
  • 一般用于测试开发
  • 直接在本地运行
package bigdata.itcast.cn.hadoop.mapreduce.wordcount;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

import java.io.IOException;

/**
 * @ClassName WordCountMr
 * @Description TODO 自定义开发实现wordcount程序
 * @Date 2020/10/30 16:36
 * @Create By     Frank
 */
public class WordCountLocal extends Configured implements Tool {

    //构建,配置,提交
    public int run(String[] args) throws Exception {
        //todo:1-构建
        Job job = Job.getInstance(this.getConf(),"userwc");
        job.setJarByClass(WordCountLocal.class);
        //todo:2-配置
        //input
        Path inputPath = new Path("D:\\IDEAProject\\SHBigdata\\datas\\wordcount\\wordcount.txt");
        TextInputFormat.setInputPaths(job,inputPath);
        //map
        job.setMapperClass(WcMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        //reduce
        job.setReducerClass(WcReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(IntWritable.class);

        //output
        Path outputPath = new Path("datas/output/wc/output1");
        TextOutputFormat.setOutputPath(job,outputPath);

        //todo:3-提交
        return job.waitForCompletion(true) ? 0:-1;
    }

    //作为程序入口,负责调用run方法
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        int status = ToolRunner.run(conf, new WordCountLocal(), args);
        System.exit(status);
    }


    public static class WcMapper extends Mapper<LongWritable, Text,Text, IntWritable>{

        //定义输出的Key:单词
        Text outputKey = new Text();
        //定义输出的Value:恒为1
        IntWritable outputValue = new IntWritable(1);

        /**
         * 每一条数据会调用一次map方法
         * @param key:K1,行的偏移量
         * @param value:V1:行的内容
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            //将每一行的内容进行分割,得到每个单词
            String[] words = value.toString().split(" ");
            //遍历取出每个单词
            for (String word : words) {
                //将单词作为Key
                this.outputKey.set(word);
                //输出:write方法用于将新的KV输出到下一步
                context.write(this.outputKey,this.outputValue);
            }

        }
    }


    public static class WcReducer extends Reducer<Text, IntWritable,Text, IntWritable>{

        //定义输出的Value
        IntWritable outputValue = new IntWritable();

        /**
         * 每一组调用一次reduce方法
         * @param key:单词
         * @param values:同一个单词对应的所有value
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
            int sum = 0;
            for (IntWritable value : values) {
                sum += value.get();
            }
            //将单词出现的次数赋值给value
            this.outputValue.set(sum);
            //输出
            context.write(key,this.outputValue);
        }
    }

}

七、MapReduce实现二手房统计

1、需求

  • 统计每个地区二手房的个数

2、分析

梅园六街坊,2室0厅,47.72,浦东,低区/6层,朝南,500,104777,1992年建
  • 结果

    地区			个数
    浦东			100
    虹口			200
    闵行
    徐汇
    ……
    
  • 有没有分组?

    • 按照地区分组
    • K2:地区
    • V2:1

3、实现

4、练习

  • 基于二手房数据统计每个地区二手房的平均单价

附录一:MapReduce编程依赖

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-mapreduce-client-core</artifactId>
        <version>2.7.5</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
    </dependency>
</dependencies>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章鱼哥TuNan&Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值