【Hadoop】MapReduce分布式计算实践(统计文本单词数量)

news2024/10/5 20:24:55

文章目录

  • 1. 前言
  • 2. Mapper代码
  • 3. Reducer代码
  • 4. Main代码
  • 5. 项目打包
  • 6. Hadoop运行
  • 7. 运行结果查看
    • 7.1 输出文件查看
    • 7.2 日志查看

1. 前言

       在博客【Hadoop】MapReduce原理剖析(Map,Shuffle,Reduce三阶段)中已经分析了MapReduce的运行过程,以及部分原理。那么这篇博客则是进行一次实践,使用MapReduce统计文本中的单词数量。实际上我们只需要写Mapper和Reducer部分的代码,最后在Main中进行一些设置即可。

2. Mapper代码

       MyMapper类继承于Mapper类,重写了map函数。map函数输入为<k1, v1>,k1为LongWritable类型,表示每一行的偏移量;v1为Text类型,表示该行内容。其实现方法为:以空格为分隔符切割单词,并将每个切除的单词写为<word, 1>的形式,表示该单词出现过一次。

public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable>{
        Logger logger = LoggerFactory.getLogger(MyMapper.class);
        /**
         * map函数接收<k1,v1>,产生<k2,v2>
         * @param k1
         * @param v1
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        @Override
        protected void map(LongWritable k1, Text v1, Mapper<LongWritable, Text, Text, LongWritable>.Context context)
                throws IOException, InterruptedException {
            //使用stdout方式输出<k1,v1>
            System.out.println("<k1,v1>=<"+k1.get()+","+v1.toString()+">");
            //使用logger方式输出<k1,v1>
            logger.info("<k1,v1>=<"+k1.get()+","+v1.toString()+">");
            //k1表示每一行的偏移量,v1表示该行内容
            //首先把每一行的单词切割出来
            String[] words = v1.toString().split(" ");
            for (String word : words) {
                Text k2 = new Text(word);
                LongWritable v2 = new LongWritable(1L);
                context.write(k2, v2);
            }
        }
    }

3. Reducer代码

       MyReducer类继承于Reduce类,重写了reduce方法。对经过Combiner的<k2,{v2s}>数据中的v2s进行求和并组成<k3,v3>。

public static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable>{
        /**
         * 对v2s的数据进行累加,保存v2s的和
         * @param k2
         * @param v2s
         * @param context
         * @throws IOException
         * @throws InterruptedException
         */
        Logger logger = LoggerFactory.getLogger(MyReducer.class);
        @Override
        protected void reduce(Text k2, Iterable<LongWritable> v2s, Reducer<Text, LongWritable, Text,
                LongWritable>.Context context) throws IOException, InterruptedException {
            //sum计算v2s的和
            long sum = 0L;
            for (LongWritable v2 : v2s) {
                System.out.println("<k2,v2>=<"+k2.toString()+","+v2.get()+">");
                logger.info("<k2,v2>=<"+k2.toString()+","+v2.get()+">");
                sum += v2.get();
            }
            Text k3 = k2;
            LongWritable v3 = new LongWritable(sum);
            System.out.println("<k3,v3>=<"+k3.toString()+","+v3.get()+">");
            logger.info("<k3,v3>=<"+k3.toString()+","+v3.get()+">");
            context.write(k3, v3);
        }
    }

4. Main代码

       由于考虑到代码的复用性,并没有将地址直接写在代码中,而是在运行前以参数形式输入。在Main函数中需要指定很多配置,如下:

  • 设置类地址:job.setJarByClass(WordCountJob.class);
  • 指定输入/输出路径,其中输入的地址可以是一个文件,也可以是一个文件夹。若是文件则对这一个文件进行切割并执行MapReduce,若是文件夹,则对该文件夹中的所有文件进行切割并执行,也就是说要执行多文件的MapReduce并不需要修改代码,只需要在输入时将其放在同一个文件夹下即可,可以说是相当方便了。
  • 指定Mapper类,以及k2和v2的类型。
  • 指定Reducer类,以及k3和v3的类型。
  • 提交job任务。
public static void main(String[] args) {
        try{
            if(args.length!=2){
                System.exit(100);
            }
            //配置项
            Configuration configuration = new Configuration();
            //创建一个job
            Job job = Job.getInstance(configuration);
            //不设置的话,集群就找不到这个类
            job.setJarByClass(WordCountJob.class);
            //指定输入路径
            FileInputFormat.setInputPaths(job, new Path(args[0]));
            //指定输出路径
            FileOutputFormat.setOutputPath(job, new Path(args[1]));

            //指定map相关的代码
            job.setMapperClass(MyMapper.class);
            //指定k2的类型
            job.setMapOutputKeyClass(Text.class);
            //指定v2的类型
            job.setOutputValueClass(LongWritable.class);

            //指定reduce相关的代码
            job.setReducerClass(MyReducer.class);
            //指定k3的类型
            job.setOutputKeyClass(Text.class);
            //指定v3的类型
            job.setOutputValueClass(LongWritable.class);

            //提交job
            job.waitForCompletion(true);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

5. 项目打包

       项目打包需要在Maven的pom.xml文件中进行一些配置,如下:

  1. 首先,添加如下打包配置,指定编码类型、jdk版本,是否打包依赖等配置。
<build>
    <plugins>
        <!-- compiler插件, 设定JDK版本 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <encoding>GBK</encoding>
                <source>1.8</source>
                <target>1.8</target>
                <showWarnings>true</showWarnings>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass></mainClass>
                    </manifest>
                </archive>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
  1. 其次,在pom中的hadoop-client和log4j依赖中增加scope属性,值为provided,表示只在编译的时候使用这个依赖,在执行以及打包的时候都不使用,因为hadoop-client和log4j依赖在集群中都是有的,所以在打jar包的时候就不需要打进去了,如果我们使用到了集群中没有的第三方依赖包就不需要增加这个provided属性了,不增加provided就可以把对应的第三方依赖打进jar包里面了。如下,在依赖中添加一行<scope>provided</scope>即可,但记得在本地运行本项目的其他程序时要注释掉!
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>3.2.0</version>
    <scope>provided</scope>
</dependency>
  1. 最后,在cmd窗口该目录下运行mvn clean package -DskipTests即可成功打包,将jar包db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jar上传到Linux系统。

打包后应该有两个jar包,分别是db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jardb_hadoop-1.0-SNAPSHOT.jar。一般来说前者与后者相比,打包的时候有依赖,但是由于本项目在依赖中添加了<scope>provided</scope>,所以在打包时并不会将依赖也打入包中,所以这两个文件是相同的。

6. Hadoop运行

       在运行前记得先给hdfs上传一个要操作的对象文件,我这里创建的是hello.txt,文件内容是:

[root@bigData01 hadoop-3.2.0]# hdfs dfs -cat /test/hello.txt
hello you
hello me
hello world

       使用命令hadoop jar db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jar MR.WordCountJob /test/hello.txt /out即可运行程序,其中各部分的含义为:

  • hadoop:表示使用hadoop脚本提交任务;
  • jar:表示执行jar包;
  • db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jar:指定具体的jar包路径信息;
  • MR.WordCountJob:指定要执行的mapreduce代码的全路径;
  • /test/hello.txt:指定mapreduce接收到的第一个参数,代表的是输入路径,这里的输入路径可以直接指定hello.txt的路径,也可以直接指定它的父目录,因为它的父目录里面也没有其它无关的文件;如果指定目录的话就意味着hdfs会读取这个目录下所有的文件,所以后期如果我们需要处理一批文件,那就可以把他们放到同一个目录里面,直接指定目录即可。
  • /out:指定mapreduce接收到的第二个参数,代表的是输出目录,这里的输出目录必须不存在;

执行结果如下:

[root@bigData01 hadoop-3.2.0]# hadoop jar db_hadoop-1.0-SNAPSHOT-jar-with-dependencies.jar MR.WordCountJob /test/hello.txt /out
2023-01-25 22:38:29,431 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
2023-01-25 22:38:30,124 WARN mapreduce.JobResourceUploader: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.
2023-01-25 22:38:30,154 INFO mapreduce.JobResourceUploader: Disabling Erasure Coding for path: /tmp/hadoop-yarn/staging/root/.staging/job_1674656126666_0003
2023-01-25 22:38:30,332 INFO input.FileInputFormat: Total input files to process : 1
2023-01-25 22:38:31,268 INFO mapreduce.JobSubmitter: number of splits:1
2023-01-25 22:38:31,293 INFO Configuration.deprecation: yarn.resourcemanager.system-metrics-publisher.enabled is deprecated. Instead, use yarn.system-metrics-publisher.enabled
2023-01-25 22:38:31,873 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1674656126666_0003
2023-01-25 22:38:31,874 INFO mapreduce.JobSubmitter: Executing with tokens: []
2023-01-25 22:38:32,092 INFO conf.Configuration: resource-types.xml not found
2023-01-25 22:38:32,092 INFO resource.ResourceUtils: Unable to find ‘resource-types.xml’.
2023-01-25 22:38:32,175 INFO impl.YarnClientImpl: Submitted application application_1674656126666_0003
2023-01-25 22:38:32,210 INFO mapreduce.Job: The url to track the job: http://bigData01:8088/proxy/application_1674656126666_0003/
2023-01-25 22:38:32,210 INFO mapreduce.Job: Running job: job_1674656126666_0003
2023-01-25 22:38:39,491 INFO mapreduce.Job: Job job_1674656126666_0003 running in uber mode : false
2023-01-25 22:38:39,491 INFO mapreduce.Job: map 0% reduce 0%
2023-01-25 22:38:45,565 INFO mapreduce.Job: map 100% reduce 0%
2023-01-25 22:38:51,623 INFO mapreduce.Job: map 100% reduce 100%
2023-01-25 22:38:52,635 INFO mapreduce.Job: Job job_1674656126666_0003 completed successfully
2023-01-25 22:38:52,719 INFO mapreduce.Job: Counters: 54

7. 运行结果查看

7.1 输出文件查看

       执行后查看/out文件夹中的文件/out/part-r-00000,这个文件即是输出的结果文件:

[root@bigData01 hadoop-3.2.0]# hdfs dfs -cat /out/part-r-00000
hello	3
me	1
world	1
you	1

7.2 日志查看

       要查看日志的话需要先配置yarn-site.xml文件,重启集群,并开启日志聚合功能:

  1. 配置yarn-site.xml文件:
<property> 
 <name>yarn.log-aggregation-enable</name> 
 <value>true</value>
 </property>
 <property>
 <name>yarn.log.server.url</name>
 <value>http://bigdata01:19888/jobhistory/logs/</value>
</property>
  1. 重启并开启日志聚合功能:
[root@bigdata01 hadoop-3.2.0]# sbin/stop-all.sh
[root@bigdata01 hadoop-3.2.0]# sbin/start-all.sh
[root@bigData01 hadoop-3.2.0]# bin/mapred --daemon start historyserver
[root@bigData01 hadoop-3.2.0]# jps
8114 NodeManager
7429 DataNode
7669 SecondaryNameNode
7239 NameNode
9159 JobHistoryServer
7945 ResourceManager
9198 Jps

       经过上述步骤后打开http://bigdata01:8088,其中bigdata01替换为你的虚拟机ip地址(我之所以写了虚拟机的名称而不是ip地址,是因为我在windows系统的hosts文件中进行过配置,若没有配置过就直接写ip),点击MapReduce任务(重启集群后会删除,因此需要再执行一次该任务)如下:

  • 点击MapReduce任务
    在这里插入图片描述
  • 点击history
    在这里插入图片描述
  • 选择自己要查看Map/Reduce任务:
    在这里插入图片描述
  • 选择Map Task/Reduce Task(通常Maptask不止一个,每个InputSplit对应一个Map task,InputSplit的计算方法以及原理在博客【Hadoop】MapReduce原理剖析(Map,Shuffle,Reduce三阶段)中已经介绍的很清楚了,感兴趣的读者可以阅览):
    在这里插入图片描述
  • 点击logs查看:
  • 查看日志,可以看到在stdout和syslog中都可以看到中间结果的输出,这是因为在写代码的时候添加了输出日志的代码,如:System.out.println("<k1,v1>=<"+k1.get()+","+v1.toString()+">"); logger.info("<k1,v1>=<"+k1.get()+","+v1.toString()+">");
    在这里插入图片描述
           至此,MapReduce分布式计算实践(统计文本单词数量)博客撰写结束,我知道这个实践很基础,也有很多博主写过这个实践过程,这篇博客就当作是我自己的学习记录,虽然很简单很基础但毕竟万丈高楼平地起嘛,让我们一起加油吧!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)

随着技术的进步&#xff0c;跨平台开发已经成为了标配&#xff0c;在此大背景下&#xff0c;ASP.NET Core也应运而生。本文主要基于ASP.NET CoreElementSql Server开发一个校园图书管理系统为例&#xff0c;简述基于MVC三层架构开发的常见知识点&#xff0c;前一篇文章&#xf…

Linux C编程一站式学习笔记6

Linux C编程一站式学习笔记 chap6 循环结构 文章目录Linux C编程一站式学习笔记 chap6 循环结构一.while语句递归 VS 循环函数式编程&#xff08;Functional Programming&#xff09; & 命令式编程&#xff08;Imperative Programming&#xff09;无限递归 & 无限循环习…

光流估计(二) FlowNet 系列文章解读

在上篇文章中&#xff0c;我们学习并解了光流&#xff08;Optical Flow&#xff09;的一些基本概念和基本操作&#xff0c;但是传统的光流估计方法计算比较复杂、成本较高。近些年来随着CNN卷积神经网络的不断发展和成熟&#xff0c;其在各种计算机视觉任务中取得了巨大成功&am…

docker-基础实战第六课镜像挂载

镜像挂载: docker run --namemynginx -d --restartalways -p 8088:80 -v /usr/local/docker/data/html:/usr/share/nginx/html:ro nginx访问403 原因: /usr/local/docker/data/html 没有创建index.html 需要创建目录并且创建index.html docker命令补充&#xff1a; 如果有一…

向QAbstractItemView子类如:QTreeView、QTableView等子项单元格插入窗体小部件的功能实现(第1种方法)

1.前言 工作中经常会遇到这样的需求&#xff1a;向QAbstractItemView子类如QTreeView、QTableView单元格插入窗体小部件&#xff0c;如&#xff1a;进度条、按钮、单行编辑框等。下面链接的系列博文就是讲解如何实现该功能的。《向QAbstractItemView子类如:QTreeView、QTableVi…

Android音频播放有杂音?原来是这个JAVA API接口惹的祸

最近在调试一个基于十年前Android版本的多媒体应用软件时&#xff0c;遇到了音频播放的问题&#xff0c;这里记录问题的发现、分析和处理过程。 有人可能会好奇&#xff0c;十年前的Android版本是什么版本&#xff1f;大家可以去Google网站上查查&#xff0c;就是目前Android网…

Android深入系统完全讲解(40)

调试 C 代码 15.1 改成 C 写法 这个没啥必要&#xff0c;但是对 C 比 C 情谊深的我&#xff0c;把它修改了。下面是修改的一部分代码&#xff0c; 把 C 的写法&#xff0c;改成 C 的&#xff0c;同时修改引入头文件。 jstring Java_hellojni_codegg_com_hellojni_MainActivity_…

Java基础41 面向对象(高级)

面向对象&#xff08;高级&#xff09;一、类变量和类方法1.1、static &#xff08;类变量&#xff09;1.1.1 关于static的存放位置1.1.2 类变量使用细节及注意事项1.2、类方法1.2.1、类方法使用细节及注意事项二、main方法2.1、深入理解main方法三、代码块3.1、代码块的基本介…

19.6、Javaweb_案例旅游路线收藏功能

旅游线路收藏功能 分析 判断当前登录用户是否收藏过该线路 当页面加载完成后&#xff0c;发送ajax请求&#xff0c;获取用户是否收藏的标记 根据标记&#xff0c;展示不同的按钮样式 编写代码 后台代码 RouteServlet&#xff1a; package cn.itcast.travel.web.servlet;…

【Typescript学习】使用 React 和 TypeScript 构建web应用(四)useReducer、扑街了的分区功能【完结了】

教程来自freecodeCamp&#xff1a;【英字】使用 React 和 TypeScript 构建应用程序 跟做&#xff0c;仅记录用 其他资料&#xff1a;https://www.freecodecamp.org/chinese/news/learn-typescript-beginners-guide/ 作者提供的源码https://github.com/piyush-eon/react-typescr…

机器学习【西瓜书/南瓜书】--- 第四章决策树

一、决策树理论分析 1.1 通俗理解 决策树是一种非常经典的机器学习算法&#xff0c;通俗理解的话我们可以举一个例子&#xff0c;比如现在别人要找你借钱&#xff0c;那么按照首先是不是要判断你和他的关系如何?如果关系不好&#xff0c;我就直接拒绝他。如果关系很好&#…

Python机器学习:一元回归

→\rightarrow→回归效果评价 &#x1f315; 一元回归 一元回归主要研究一个自变量和一个因变量之间的关系&#xff0c;而这个自变量和因变量之间的关系又可分为线性回归和非线性回归。 ⭐️ 一元线性回归分析两个变量之间的线性关系&#xff0c;如ykxbykxbykxb中xxx和yyy就是…

深度学习笔记:神经网络的学习(1)

机器学习的核心在于从数据中提取规律和特征&#xff0c;并用于分类或预测。对于识别手写数字&#xff0c;如果人工设计一个识别算法逻辑是十分困难的。一种方法是任务在数据中提取更重要的特征量&#xff0c;然后利用机器学习算法如SVM或KNN。而神经网络的方法则是完全由机器自…

ISIS的3级别(level-1、level-2、level-1-2)4大类(IIH、LSP、CSNP、PSNP)9小类与邻接关系建立LSP交互过程介绍

2.2.0 ISIS 4种报文类型IIH、LSP、CSNP、PSNP、邻居建立过程、交互LSP过程 ISIS的3级别4大类9小类 ISIS拥有3种级别的路由器&#xff0c;分别是level-1、level-2、level-1-2。 不同级别之间进行交互的报文也是有所区别的&#xff0c;常规的ISIS报文分有4大类&#xff1a;IIH、…

cubeIDE开发, stm32人工智能开发应用实践(Cube.AI).篇一

一、cube.AI简介及cubeIDE集成 1.1 cube.AI介绍 cube.AI准确来说是STM32Cube.AI&#xff0c;它是ST公司的打造的STM32Cube生态体系的扩展包X-CUBE-AI&#xff0c;专用于帮助开发者实现人工智能开发。确切地说&#xff0c;是将基于各种人工智能开发框架训练出来的算法模型&#…

Vue3商店后台管理系统设计文稿篇(六)

记录使用vscode构建Vue3商店后台管理系统&#xff0c;这是第六篇&#xff0c;从这一篇章开始&#xff0c;所有的预备工作结束&#xff0c;正式进入商店后台管理系统的开发 文章目录一、创建后台管理系统的标题栏二、安装Icon 图标三、创建Menu菜单正文内容&#xff1a; 一、创…

PowerShell 学习笔记:操作JSON文件

JSON文件&#xff08;字符串&#xff09;是有一定格式要求的文本文件。百度百科JSON&#xff08;JavaScriptObject Notation, JS对象简谱&#xff09;是一种轻量级的数据交换格式。它基于 ECMAScript&#xff08;European Computer Manufacturers Association, 欧洲计算机协会制…

初识Linux常见指令汇总

文章目录前言1.对文件或目录的常用指令1.查看当前路径下的文件或目录相关信息2.进入指定路径3.创建删除文件或者目录4.使用nano简单编辑文件查看文件属性5.复制移动重命名文件或目录6.输入输出重定(查看文件内容)向和搜索查找1.输入输出重定向2.搜索查找7.打包压缩文件2.时间相…

如何使用Maven构建Java项目?Maven的使用详细解读

文章目录1. 前言2. Maven 快速入门2.1 Maven 项目模型2.2 Maven 仓库3. Maven的安装配置3.1 安装3.2 配置环境变量3.4 Maven 配置4. Maven 的常用命令4.1 编译4.2 清理4.3 打包4.4 测试4.5 安装5. Maven生命周期6. 总结Java编程基础教程系列&#xff1a;1. 前言 在 Java 开发中…

C++初阶:list类

文章目录1 list介绍2 list的模拟实现2.1 类的定义2.2 默认成员函数2.2.1 构造函数2.2.2 析构函数2.2.3 拷贝构造2.2.4 赋值重载2.3 迭代器2.3.1 正向迭代器2.3.2 反向迭代器2.4 修改接口2.4.1 任意位置插入2.4.2 任意位置删除2.5 其他接口2.5.1 尾插2.5.2 头插2.5.3 尾删2.5.3 …