手写MapReduce实现WordCount

水善利万物而不争,处众人之所恶,故几于道💦

文章目录

      • 需求
      • 分析
      • 编写MapReduce实现上述功能
        • Mapper类
        • Reducer类
        • Driver类
      • 查看输出结果

需求

  假设有一个文本文件word.txt,我们想要统计这个文本文件中每个单词出现的次数。
文件内容如下:

在这里插入图片描述
期望输出结果:
在这里插入图片描述

分析

  根据MapReduce的思想,整体分为两个过程一个是Map阶段,一个是Reduce阶段。可以粗略得出下面几步:
  ①将读取到的数据进行单词间的拆分,拆出来一个一个的单词。
  ②将每个单词出现的次数标记为1。eg:(hello,1)、(qcln,1)…
  ③然后相同单词进入一个ReduceTask,进行value值的累加,也就算出了这个单词出现的次数。
  ④将最终的结果输出。

在这里插入图片描述

编写MapReduce实现上述功能

要先添加Hadoop的项目依赖(建Maven项目)

<dependencies>
    <dependency>
        <!-- Hadoop的项目依赖-->
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <!--这个可加可不加,是为了在控制台打印日志的,
        加上的话要在resources目录下建一个log4j.properties配置文件-->
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>

resources目录下log4j.properties配置文件内容:

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

项目目录结构:
在这里插入图片描述

编写MapReduce程序的话要写三个类Mapper、Reducer、Driver

Mapper类:继承Mapper类,重写map方法。每行数据读进来后,他都要调用map方法对数据进行处理,处理完后,再把数据写回框架,让框架处理。

Recuder类:继承Reducer类,重写reduce方法。key值相同的数据会进入同一个reduce方法,这个阶段会调用reduce方法对这一组key值相同的数据进行处理。

Driver类:整个MapReduce程序的入口,在这个类中写main方法。这个类主要是创建一个job实例,然后给job赋值(指定Mapper类、Reducer类、Mapper输出的key value类型、最终结果输出的key value类型、Map Reduce程序的读取文件路径和结果输出路径),最后提交该job

Mapper类
package com.daemon.mr.wordcount;

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

import java.io.IOException;

/**
 * Author: Pepsi
 * Date: 2023/12/21
 * Desc:
 */

/*
* Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
    泛型含义:
        1.偏移量:是一行中数据的偏移量,可以理解成这一行数据长度的样子。
          比如第一行  abcde  第二行 qwe,假如第一行的偏移量是0,第二行的偏移量可能就是8
          这个类型只能为LongWritable类型,偏移量比较大
        2.读到的每行数据的类型
        3.输出的key的类型  因为这里词频统计map后想要输出(aaa,2)这种形式,所以key是Text value是LongWritable类型
        4.输出的value的类型
    
    这个类主要的作用就是封装kv对也就是标记,
    也就是WordCount需求中将每行数据处理为(hello,1)这种格式
* */
public class WCMappre extends Mapper<LongWritable,Text, Text, LongWritable> {
		
    // 创建一个输出键的对象,待会儿取到数据后直接赋值给他,然后写出去
    // 定义在map外面就不用频繁创建对象了
    private Text outKey = new Text();
    // 创建一个输出值的对象,也就是那个频率,这里直接给他初始化为1,直接用  
    private LongWritable outValue = new LongWritable(1);

    /**
     *
     * @param key 读取到每行数据的偏移量
     * @param value  读取到的那一行数据
     * @param context 上下文对象,可以理解为程序本身,因为是框架下编程,所以处理结果要还给框架
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //super.map(key, value, context);

        //System.out.println("这是偏移量:"+key);

	    //将读取到的一行数据转换为字符串类型(Text类型是Hadoop的类型没法切割)
	    // 然后按照空格切分,因为要读取的数据文件中单词之间使用空格分开的
        String[] words = value.toString().split(" ");
		// 得到这一行的单词数组后,进行遍历每个单词
        for (String word : words) {
        	// 将上面创建好的Text对象的值设置为当前遍历到的单词 ==> outKey=qcln  outValue=1
            outKey.set(word);
            // 写回框架,后续交给框架处理   ==> (qcln,1)
            context.write(outKey,outValue);
        }

    }
}
Reducer类
package com.daemon.mr.wordcount;

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

import java.io.IOException;

/**
 * Author: Pepsi
 * Date: 2023/12/21
 * Desc:
 */

/*
Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
1.输入的key的类型 也就是Map阶段输出key的类型
2.输入的value的类型  也就是Map阶段输出的value的类型
3.最终结果输出的key的类型  也就是写出到文件中的key的类型,是单词,所以是Text类型
4.最终的结果输出的value的类型 也就是写出到文件中的value的类型,是单词出现的次数,所以是LongWritable类型(IntWritable也行,只不过如果数据量大,怕IntWritable放不下)
 */
public class WCReducer extends Reducer<Text, LongWritable,Text,LongWritable> {

	// 用来存放单词出现的总次数,最后要将他写出去
    private LongWritable outVale = new LongWritable();
    /**
     *
     * @param key map结果输出的key
     * @param values 相同key的所有值
     * @param context 上下文
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
        //super.reduce(key, values, context);

		// 累加变量,存放单词出现的总次数,待会要把这个结果赋给LongWritable,然后写出去
        long count = 0;
		// 遍历每个value
        for (LongWritable value : values) {
            // get()方法返回一个long类型的值
            count+=value.get();
        }
        // 将long类型的累加变量赋值给LongWritable => outVale=2
        outVale.set(count);
        // 将结果写出去 => (qcln,2)
        context.write(key,outVale);

    }
}
Driver类
package com.daemon.mr.wordcount;

import org.apache.hadoop.conf.Configuration;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * Author: Pepsi
 * Date: 2023/12/21
 * Desc:
 */
public class WCDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        
        Configuration conf = new Configuration();
        // 1. 创建job实例,可以不传conf,传的话可以用conf.set(key,value)进行一些配置
        Job job = Job.getInstance(conf);
        
		// 2. 给job赋值
		// 设置jar的入口类,如果是本地运行可以不写,如果想要将项目打jar包扔在集群上运行必须写
        job.setJarByClass(WCDriver.class);
		// 指定Mapper和Reducer类
        job.setMapperClass(WCMappre.class);
        job.setReducerClass(WCReducer.class);
		// 设置Mapper输出的key value 类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);
		// 设置整个程序输出的key value类型 -- Reducer的输出也就是整个程序的输出,所以也可以理解为Reducer的输出类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);
		// 设置程序从哪读取文件,将结果输出到哪,输出目录不能存在
        FileInputFormat.setInputPaths(job,new Path("D:\\word.txt"));
        FileOutputFormat.setOutputPath(job,new Path("D:\\output"));

		// 3. 提交job,运行。 也可以不接收这个返回值
        boolean b = job.waitForCompletion(true);
		// 程序结束返回的状态码
        System.exit(b ? 0 : 1);
    }
}

查看输出结果

在这里插入图片描述在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265264.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【内存泄露】记一次内存泄露排查,罪魁祸首是HttpClient

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不仅仅是技术还有人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔 !序言 很久很久以前,曾经的青葱…

docker构建镜像及项目部署

文章目录 练习资料下载一、docker基础1. 基本概念2. docker常见命令3. 命令别名4. 数据卷 二、docker自定义镜像1. 了解镜像结构2. 了解Dockerfile3. 构建Dockerfile文件&#xff0c;完成自定义镜像 三、网络1. docker常见网络命令2. docker自带虚拟网络3. 自定义网络 四、dock…

【3D Max】入门

文章目录 概述界面介绍常用功能保存和导入基本建模编辑模型材质和贴图光源和阴影动画制作渲染设置导出和打印来源 概述 3 ds MAX是由 Discreet (后来被 Autodesk (Autodesk)合并)开发的一款基于 PC系统的3 d Max或3 ds MAX三维动画绘制和制作软件&#xff0c;其主要功能有建模…

【精选】vulnhub CTF6 linux udev提权 (青铜门笔记)

一、信息收集 1.主机探测 发现靶机的IP地址是&#xff1a;192.168.103.130 ┌──(root&#x1f480;kali)-[~] └─# arp-scan -l2.访问web页面 发现有个登录的页面&#xff0c;尝试了弱口令&#xff0c;但是发现没有成功&#xff1b; 所以&#xff0c;我们需要在后面的信…

Go 泛型发展史与基本介绍

Go 泛型发展史与基本介绍 Go 1.18版本增加了对泛型的支持&#xff0c;泛型也是自 Go 语言开源以来所做的最大改变。 文章目录 Go 泛型发展史与基本介绍一、为什么要加入泛型&#xff1f;二、什么是泛型三、泛型的来源四、为什么需要泛型五、Go 泛型设计的简史六、泛型语法6.1 …

Netty RPC 实现(二)

Netty RPC 实现 概念 RPC&#xff0c;即 Remote Procedure Call&#xff08;远程过程调用&#xff09;&#xff0c;调用远程计算机上的服务&#xff0c;就像调用本地服务一样。RPC 可以很好的解耦系统&#xff0c;如 WebService 就是一种基于 Http 协议的 RPC。这个 RPC 整体…

机器视觉兄弟们,出身寒微,不是耻辱,能屈能伸,方为丈夫

人生过往&#xff0c;当时只道是寻常。 可以说&#xff0c;“社会边角料”这个词&#xff0c;即刺耳&#xff0c;又是那么难听。只是&#xff0c;无数的年轻人和中年人&#xff0c;都喜欢用这个词来自嘲。 特别是出身寒微&#xff0c;没啥资源的80后和90后&#xff0c;他们总是…

C语言的分支和循环语句

各位少年&#xff0c;今天和大家分享的是分支语句循环体语句&#xff0c;C语言是结构体的程序设计语言&#xff0c;这里的结构指的是&#xff08;顺序结构&#xff09;&#xff08;选择结构&#xff09;&#xff08;循环结构&#xff09;C语言是能够实现这三种结构的&#xff0…

docker容器内 获取宿主机ip

可以使用命令 --add-host jargatewayip:192.168.0.47 \ 需要注意,这里不能是 127.0.0.1 ,所以要找到服务器局域网的ip 命令示例 docker run -it \-p 80:80 \-p 443:443 \--name nginx \--network app --hostname nginx \-e TZAsia/Shanghai \--add-host jargatewayip:192.16…

fabs函数与fmax函数

目录 fabs函数 fmax函数 fabs函数 包含头文件&#xff1a;<math.h> C90函数原型&#xff1a;double fabs (double x); C99函数原型&#xff1a; double fabs (double x); float fabsf (float x);long double fabsl (long double x); C98函数原型&#xff1a; doubl…

第11章 GUI Page421~422 步骤六 支持文字

运行效果&#xff1a; 关键代码&#xff1a; 新增头文件&#xff1a; //item_text.hpp #ifndef ITEM_TEXT_HPP_INCLUDED #define ITEM_TEXT_HPP_INCLUDED #include "item_i.hpp"class TextItem : public IItem { public:TextItem(): _startPosition(0, 0), _endPos…

ssm基于BS的库存管理软件设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

【操作系统】补充:你看到的所有地址都不是真的

补充&#xff1a;你看到的所有地址都不是真的 写过打印出指针的 C 程序吗&#xff1f;你看到的值&#xff08;一些大数字&#xff0c;通常以十六进制打印&#xff09;是虚拟地址&#xff08;virtual address&#xff09;。有没有想过你的程序代码在哪里找到&#xff1f;你也可以…

【华为鸿蒙系统学习】- 如何利用鸿蒙系统进行App项目开发|自学篇

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 创建鸿蒙第一个App项目 项目创建 工程目录区 预览区 运行Hello World 基本工程目录 ws:工程…

HarmonyOS 点击物理返回键再按一次退出系统(eTS)

&#xff08;1&#xff09;首先&#xff0c;定义一个变量&#xff0c;用于计算用户两次按下返回键的时间差&#xff1a; //todo 定义全局变量State exitTime: number 0;&#xff08;2&#xff09;然后就是一个捕捉用户按下返回键的事件&#xff1a; //todo 定义全局变量State …

计算球的体积 C语言xdoj89

题目描述&#xff1a;输入球的半径&#xff0c;计算并输出球的体积,假定pi3.14&#xff0c;结果保留两位小数。 输入格式&#xff1a;共一行&#xff0c;输入球体半径&#xff0c;两位小数。 输出格式&#xff1a;共一行&#xff0c;输出球体体积&#xff0c;结果保留两位小数。…

SecureCRT连接vmware虚拟机的centos系统配置

软件版本&#xff1a;VMware10.0.3&#xff0c;centos 7&#xff0c;securecrt 8.7.2 1&#xff0c;虚拟网络编辑器选择桥接模式&#xff0c; 2&#xff0c;如果不小心删除网络&#xff0c;centos关机状态下&#xff0c;选择恢复默认设置。 3&#xff0c;进入linux系统&#…

基于ssm重庆理工大学心理咨询管理子系统的分析与实现论文

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;心理咨询预约信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能…

Arduino开发实例-APDS-9930环境光和趋近传感器驱动

APDS-9930环境光和趋近传感器驱动 文章目录 APDS-9930环境光和趋近传感器驱动1、APDS-9930介绍2、硬件准备及接线3、驱动实现1、APDS-9930介绍 APDS-9930模块由环境光、红外线和接近传感器组成。 检测距离可达 100 毫米。 APDS-9930 传感器测量环境光。 该传感器还可以在黑暗中…

深入理解qs库:简化你的工作流程

前言 在 vue 开发中&#xff0c;处理 url 查询字符串是一个常见的任务。qs 库是一个流行的工具&#xff0c;可以帮助我们轻松地处理 url 查询字符串的编码和解码。本文将介绍 qs 库的基本用法&#xff0c;并结合实例演示帮助你更好地理解和应用这个实用的工具。 一、qs 是什么&…