上一篇博文如何在Eclipse下搭建Hadoop开发环境,今天给大家介绍一下如何分别分别在Eclipse和Hadoop集群上运行我们的MapReduce程序!

1. 在Eclipse环境下运行MapReduce程序(WordCount程序)

  首先看一下我的项目结构和WordCount程序:

  其中word.txt将作为我们测试的输入文件,内容如下:

  程序代码如下所示:

 package com.hadoop.WordCount;

 import java.io.IOException;
import java.util.StringTokenizer;
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.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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; @SuppressWarnings("unused")
public class WordCount { public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable>
// 为什么这里k1要用Object、Text、IntWritable等,而不是java的string啊、int啊类型,当然,你可以用其他的,这样用的好处是,因为它里面实现了序列化和反序列化。
// 可以让在节点间传输和通信效率更高。这就为什么hadoop本身的机制类型的诞生。 //这个Mapper类是一个泛型类型,它有四个形参类型,分别指定map函数的输入键、输入值、输出键、输出值的类型。hadoop没有直接使用Java内嵌的类型,而是自己开发了一套可以优化网络序列化传输的基本类型。
//这些类型都在org.apache.hadoop.io包中。
//比如这个例子中的Object类型,适用于字段需要使用多种类型的时候,Text类型相当于Java中的String类型,IntWritable类型相当于Java中的Integer类型
{
//定义两个变量或者说是定义两个对象,叫法都可以
private final static IntWritable one = new IntWritable(1);//这个1表示每个单词出现一次,map的输出value就是1.
//因为,v1是单词出现次数,直接对one赋值为1
private Text word = new Text(); public void map(Object key, Text value, Context context)
//context它是mapper的一个内部类,简单的说顶级接口是为了在map或是reduce任务中跟踪task的状态,很自然的MapContext就是记录了map执行的上下文,在mapper类中,这个context可以存储一些job conf的信息,比如job运行时参数等,
//我们可以在map函数中处理这个信息,这也是Hadoop中参数传递中一个很经典的例子,同时context作为了map和reduce执行中各个函数的一个桥梁,这个设计和Java web中的session对象、application对象很相似
//简单的说context对象保存了作业运行的上下文信息,比如:作业配置信息、InputSplit信息、任务ID等
//我们这里最直观的就是主要用到context的write方法。
//说白了,context起到的是连接map和reduce的桥梁。起到上下文的作用! throws IOException, InterruptedException {
//The tokenizer uses the default delimiter set, which is " \t\n\r": the space character, the tab character, the newline character, the carriage-return character
StringTokenizer itr = new StringTokenizer(value.toString());//将Text类型的value转化成字符串类型 //使用StringTokenizer类将字符串“hello,java,delphi,asp,PHP”分解为单个单词
// 程序的运行结果为:
// hello
// java
// delphi
// asp
// php while (itr.hasMoreTokens()) {
// 实际上就是java.util.StringTokenizer.hasMoreTokens()
// hasMoreTokens() 方法是用来测试是否有此标记生成器的字符串可用更多的标记。
word.set(itr.nextToken());
context.write(word, one);
}
}
} public static class IntSumReducer extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
//我们这里最直观的就是主要用到context的write方法。
//说白了,context起到的是连接map和reduce的桥梁。起到上下文的作用! int sum = 0;
for (IntWritable val : values) {//叫做增强的for循环,也叫for星型循环
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
} public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();//程序里,只需写这么一句话,就会加载到hadoop的配置文件了
//Configuration类代表作业的配置,该类会加载mapred-site.xml、hdfs-site.xml、core-site.xml等配置文件。 //删除已经存在的输出目录
Path mypath = new Path("hdfs://Centpy:9000/test/wordcount-out");//输出路径
FileSystem hdfs = mypath.getFileSystem(conf);//程序里,只需写这么一句话,就可以获取到文件系统了。
//FileSystem里面包括很多系统,不局限于hdfs,是因为,程序读到conf,哦,原来是hadoop集群啊。这时,才认知到是hdfs //如果文件系统中存在这个输出路径,则删除掉,保证输出目录不能提前存在。
if (hdfs.isDirectory(mypath)) {
hdfs.delete(mypath, true);
} //job对象指定了作业执行规范,可以用它来控制整个作业的运行。
Job job = Job.getInstance();// new Job(conf, "word count");
job.setJarByClass(WordCount.class);//我们在hadoop集群上运行作业的时候,要把代码打包成一个jar文件,然后把这个文件
//传到集群上,然后通过命令来执行这个作业,但是命令中不必指定JAR文件的名称,在这条命令中通过job对象的setJarByClass()中传递一个主类就行,hadoop会通过这个主类来查找包含它的JAR文件。 job.setMapperClass(TokenizerMapper.class);
//job.setReducerClass(IntSumReducer.class);
job.setCombinerClass(IntSumReducer.class);//Combiner最终不能影响reduce输出的结果
// 这句话要好好理解!!! job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//一般情况下mapper和reducer的输出的数据类型是一样的,所以我们用上面两条命令就行,如果不一样,我们就可以用下面两条命令单独指定mapper的输出key、value的数据类型
//job.setMapOutputKeyClass(Text.class);
//job.setMapOutputValueClass(IntWritable.class);
//hadoop默认的是TextInputFormat和TextOutputFormat,所以说我们这里可以不用配置。
//job.setInputFormatClass(TextInputFormat.class);
//job.setOutputFormatClass(TextOutputFormat.class); FileInputFormat.addInputPath(job, new Path(
"hdfs://Centpy:9000/test/word.txt"));//FileInputFormat.addInputPath()指定的这个路径可以是单个文件、一个目录或符合特定文件模式的一系列文件。
//从方法名称可以看出,可以通过多次调用这个方法来实现多路径的输入。
FileOutputFormat.setOutputPath(job, new Path(
"hdfs://Centpy:9000/hdfsOutput"));//只能有一个输出路径,该路径指定的就是reduce函数输出文件的写入目录。
//特别注意:输出目录不能提前存在,否则hadoop会报错并拒绝执行作业,这样做的目的是防止数据丢失,因为长时间运行的作业如果结果被意外覆盖掉,那肯定不是我们想要的
System.exit(job.waitForCompletion(true) ? 0 : 1);
//使用job.waitForCompletion()提交作业并等待执行完成,该方法返回一个boolean值,表示执行成功或者失败,这个布尔值被转换成程序退出代码0或1,该布尔参数还是一个详细标识,所以作业会把进度写到控制台。
//waitForCompletion()提交作业后,每秒会轮询作业的进度,如果发现和上次报告后有改变,就把进度报告到控制台,作业完成后,如果成功就显示作业计数器,如果失败则把导致作业失败的错误输出到控制台
}
} //TextInputFormat是hadoop默认的输入格式,这个类继承自FileInputFormat,使用这种输入格式,每个文件都会单独作为Map的输入,每行数据都会生成一条记录,每条记录会表示成<key,value>的形式。
//key的值是每条数据记录在数据分片中的字节偏移量,数据类型是LongWritable.
//value的值为每行的内容,数据类型为Text。
//
//实际上InputFormat()是用来生成可供Map处理的<key,value>的。
//InputSplit是hadoop中用来把输入数据传送给每个单独的Map(也就是我们常说的一个split对应一个Map),
//InputSplit存储的并非数据本身,而是一个分片长度和一个记录数据位置的数组。
//生成InputSplit的方法可以通过InputFormat()来设置。
//当数据传给Map时,Map会将输入分片传送给InputFormat(),InputFormat()则调用getRecordReader()生成RecordReader,RecordReader则再通过creatKey()和creatValue()创建可供Map处理的<key,value>对。
//
//OutputFormat()
//默认的输出格式为TextOutputFormat。它和默认输入格式类似,会将每条记录以一行的形式存入文本文件。它的键和值可以是任意形式的,因为程序内部会调用toString()将键和值转化为String类型再输出。

  接下来我们右键选择“Run As --> Java Aplication / Run on Hadoop”运行程序,控制台情况如下:

  然后,右键我们的DFS Locations,执行刷新命令,此时运行结果也出现在目录里了,如下所示:

  具体内容如下:

  显然这是正确的结果。

2. 在Hadoop集群上运行MapReduce程序(WordCount程序)

  在导出为jar包之前需要对代码进行一点小小的修改。在Eclipse环境下运行时我们需要将输入输出目录写死才能正常执行,但在Hadoop上执行时需要更灵活的方法,所以使用数组(args[])来代替,在执行运行命令时再指定路径!(这一点很重要,否则会报错而无法运行)。

  接下来,我们需要将我们的项目导出为Jar包。

  然后使用rz命令(如果没有安装请使用命令进行安装,-y表示直接确认,在后面的安装过程可以不用再等待确认)上传到Hadoop目录下。

    yum -y install lrzsz

 上传之后我们输入以下命令来运行我们的MapReduce程序。

hadoop jar WordCount.jar com.hadoop.WordCount.WordCount /test /hdfsOutput

  其中,.jar文件为我们上传的程序,第二个红框里的路径为Eclipse下的类及完整路径(包路径+类名),运行过程如下所示:

  现在输入以下命令以查看输出路径及结果文件:

hadoop fs -ls /hdfsOutput
hadoop fs -cat /hdfsOutput/part-r-00000

  显然,结果和在Eclipse环境下的一致。

  本文内容就到此结束了,希望大家通过阅读本文之后能够明白在这两个不同环境下运行MapReduce程序的具体流程、区别以及注意事项。

以上就是博主为大家介绍的这一板块的主要内容,这都是博主自己的学习过程,希望能给大家带来一定的指导作用,有用的还望大家点个支持,如果对你没用也望包涵,有错误烦请指出。如有期待可关注博主以第一时间获取更新哦,谢谢!

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

MapReduce编程入门实例之WordCount:分别在Eclipse和Hadoop集群上运行的更多相关文章

  1. hadoop 把mapreduce任务从本地提交到hadoop集群上运行

    MapReduce任务有三种运行方式: 1.windows(linux)本地调试运行,需要本地hadoop环境支持 2.本地编译成jar包,手动发送到hadoop集群上用hadoop jar或者yar ...

  2. [转]Hadoop集群_WordCount运行详解--MapReduce编程模型

    Hadoop集群_WordCount运行详解--MapReduce编程模型 下面这篇文章写得非常好,有利于初学mapreduce的入门 http://www.nosqldb.cn/1369099810 ...

  3. 将java开发的wordcount程序提交到spark集群上运行

    今天来分享下将java开发的wordcount程序提交到spark集群上运行的步骤. 第一个步骤之前,先上传文本文件,spark.txt,然用命令hadoop fs -put spark.txt /s ...

  4. Eclipse连接Hadoop集群及WordCount实践

    声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 一.环境准备 1.JDK安装与配置 2.Eclipse下载 下载解压即可,下载地址:https://pan.baidu.com/s/1i51UsVN ...

  5. Hadoop集群WordCount运行详解(转)

    原文链接:Hadoop集群(第6期)_WordCount运行详解 1.MapReduce理论简介 1.1 MapReduce编程模型 MapReduce采用"分而治之"的思想,把对 ...

  6. windows下eclipse远程连接hadoop集群开发mapreduce

    转载请注明出处,谢谢 2017-10-22 17:14:09  之前都是用python开发maprduce程序的,今天试了在windows下通过eclipse java开发,在开发前先搭建开发环境.在 ...

  7. hadoop问题锦集(一):mapreduce不能在集群中运行

    问题详细: 搭建类hadoop的集群集群环境,查看hadoop dfsadmin -report 也有datanode节点.在master:50070上也有. 然而在eclipse环境上运行mapre ...

  8. 实训任务04 MapReduce编程入门

    实训任务04 MapReduce编程入门 1.实训1:画图mapReduce处理过程 使用有短句“A friend in need is a friend in deed”,画出使用MapReduce ...

  9. 指导手册05:MapReduce编程入门

    指导手册05:MapReduce编程入门   Part 1:使用Eclipse创建MapReduce工程 操作系统: Centos 6.8, hadoop 2.6.4 情景描述: 因为Hadoop本身 ...

随机推荐

  1. dead reckoning variation

    Targeting A target is a structure of information that describes the state, and change of state, of a ...

  2. leetcode 304. Range Sum Query 2D - Immutable(递推)

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

  3. iOS UINavgationController、 UINavigationBar、 UINavigationItem关系分析

    一般导航控制器含有4个对象,UINavigationController.UINavigationBar.UIViewController.UINavigationItem. 1:UINavigati ...

  4. bzoj 4753 [Jsoi2016]最佳团体——0/1分数规划

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4753 0/1分数规划裸题. #include<iostream> #includ ...

  5. The current .NET SDK does not support targeting .NET Core 2.2

    The current .NET SDK does not support targeting .NET Core 2.2 1. 奇怪的错误 最近遇到了一件奇怪的事, The current .NET ...

  6. 搭建基于Nagios的监控系统——之监控远程Windows服务器

    分享了如何监控Linux服务器,我们来看看使用Nagios如何监控Windows服务器. 第一部分:配置被监控的Windows服务器   首先,访问 http://sourceforge.net/pr ...

  7. css3 翻起页脚

    html <div class="demo2"> <img src="images/1.jpg"> </div> css . ...

  8. 一 Kubernetes介绍

    Kubenetes是一款由Google开发的开源的容器编排工具,它可以解决以下分布式环境下的问题: 调度 你已经得到了这个很棒的基于容器的应用程序? 太棒了!现在你需要确保它能够运行在它应该运行的地方 ...

  9. JAVA 编程思想二

    1: java  单根继承的优点? 方便垃圾回收: 垃圾回收的设计会方便实现.   多重继承的函数重名的问题. 2: 向下转型和向上转型?    向下转型不安全,向上转型安全. 3: system.g ...

  10. Lagom学习 六 Akka Stream

    lagom中的stream 流数据处理是基于akka stream的,异步的处理流数据的.如下看代码: 流式service好处是: A: 并行:  hellos.mapAsync(8, name -& ...