明白了MapReduce程序的工作原理之后,下一步就是写代码来实现它。我们需要三样东西:一个map函数、一个reduce函数和一些用来运行作业的代码。map函数由Mapper类来表示,后者声明一个map()虚方法。范例2-3显示了我们的map函数实现。

范例2-3 查找最高气温的Mapper类

Import java.Io.IOException;
import org.apahce.hadoop.io.IntWritable;
import org.apahce.hadoop.io.LongWritable;
import org.apahce.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; public class MaxTemperatureMapper extends MapReduceBase implements Mapper<LongWritable,Text,Text,IntWritable>{ private static final int MISSING = 9999; @Override
public void map(LongWritable key,Text value,Context context) throws IOException,InterruptedException{
String line = value.toString();
String year = line.substring(15,19);
int airTemperature; if(line.charAt(87) =='+'){
airTemperature = Integer.parseInt(line.substring(88,92));
else{
airTemperature = Integer.parseInt(line.subtring(87,92));
}
String quality = line.substring(92,93);
if(airTemperature != MISSING &&quality.matches("[01459]")){
context.write(new Text(year),new IntWritetable(airTemperature));
} } } }

这个Mapper类是一个泛型类型,他有四个行参类型,分别指定:map函数的输入键,输入值,输出键和输出值的类型。就现在的例子来说,输入键是一个长整数偏移量,输入值是一行文本,输出键是年份,输出值是气温(整数)。Hadoop本身提供了一套可优化网络序列化传输的基本类型,而不直接使用Java内嵌的类型。这些类型都在org.apache.hadoop.io包中。这里使用LongWritable类型(相当于Java的Long类型)、Text类型(相当于Java的String类型)和IntWritable类型(相当于Java的Integer类型)。

map()方法的输入时一个键和一个值。我们首先将包含有一行输入的Text值转换成Java的String类型,之后使用substring()方法提取我们感兴趣的列。

map()方法还提供了Context实例用于输出内容的写入。在这种情况下,我们将年份按Text对象进行读/写(因为我们把年份当作键),将气温值封装在IntWritable类型中。只有气温数据不缺并且对应质量代码显示为正确的气温读数时,这些数据才会被写入输出记录中。

以类似方法用Reducer来定义reduce函数,如范例2-4所示。

范例2-4.查找最高气温的Reducer类

import  java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apche.hadoop.io.Text;
import org.apche.hadoop.mapreduce.Reducer; public class MaxTemperatureReducer extends Reducer<Text,IntWritable,Text,IntWritable>{ @Overide public void reduce(Text key,Interable<IntWritable> values,Context context){
int maxValue = Integer.MIN_VALUE;
for(IntWritable value:values){
maxValue = Max.max(maxValue,value.get());
}
context.write(key,new IntWritable(maxValue)); } }

同样,reduce函数也有四个形式参数类型用于指定输入和输出类型。reduce函数的输入类型必须匹配map函数的输出类型:即Text类型和IntWritable类型。在这种情况下,reduce函数的输出类型也必须是Text和IntWritable类型,分别输出年份及其最高气温。这个最高气温是通过循环比较每个气温与当前所知最高气温所得到的。

第三部分代码负责运行MapReduce作业(请参见范例2-5)

范例2-5 这个应用程序在气象数据集中找出最高气温

import java.oo.IOException;
import org.apache.hadoop.fs.Path;
import org.apahce.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.input.FileOutputFormat;
import org.apache.hadoop.mapreduce.input.FileOutputFormat; public class MaxTemperature{ public static void main(String[] args) throws Exception{ if(args.length !=2){
System.err.printlin("Usage:MaxTemperature<input path> <output path>");
System.exit(-1); } Job job = new Job();
job.serJarByClass(MaxTemperature.class);
job.setName("Max temperature"); FileInputFormat.addInputPath(job,new Path(args[0]));
FileOutputFormat.setOutputPath(job,new Path([args[1])); job.setMapperClass(MaxTemperatureMapper,class);
job.setReducerClass(MaxTemperatureReducer.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); System.exit(job.waitForCompletion(true)?0:1); } }

Job对象可以指定作业执行规范。我们可以用它来控制整个作业的运行。我们在Hadoop集群上运行这个作业时,要把代码打包成一个Jar文件(Haoop在集群上发布在合格文件)。

不必明确指定JAR文件的名称,在Job对象的setJarByClass()方法中传递一个类即可,Hadoop利用这个类来查找包含它的JAR文件,进而找到相关的Jar文件。

构造Job对象之后,需要指定输入和输出数据的路径。调用FileInputFormat类的静态方法addInputPath()来定义输入数据的路径,这个路径可以是单个的文件、一个目录(此时,将目录下所有文件当做输入)或符合特定文件模式的一系列文件。由函数名可知,可以多次调用addInputPath()来实现多路径的输入。

调用FileOutputFormat类中的静态方法setOutputPath()来指定输出路径(只能有一个输出路径)。这个方法指定的是reduce函数输出文件的写入目录。在运行作业前该目录是不应该存在的,否则Hadoop会报错并拒绝运行作业。这种预防措施的目的是放置数据丢失(长时间运行的作业如果结果被意外覆盖,肯定是非常恼人的)。

接着,调用setMapperClas()和setReducerClass()指定map类型和reduce类型。
setOutputKeyClass()和setOutputValueClass()控制map和reduce函数的输出类型,正如本例所示,这两个输出类型一般都是相同的。如果不同,则通过setMapOutputKeyClass()和setMapOutputValueClass()来设置mao函数的输出类型。

输入的类型通过InputFormat类来控制,我们的例子中没有设置,因为使用的是默认的TextInputFormat(文本输入格式)。

在设置定义map和reduce函数的类之后,可以开始运行作业。Job中的waitForCompletion()方法提交作业并等待执行完成。该方法中的布尔参数是个详细标识,所以作业会把进度写到控制台。

waitForCompletion()方法返回一个布尔值,表示执行的成(true)败(false)。

Java 实现MapReduce函数的更多相关文章

  1. 简单的java Hadoop MapReduce程序(计算平均成绩)从打包到提交及运行

    [TOC] 简单的java Hadoop MapReduce程序(计算平均成绩)从打包到提交及运行 程序源码 import java.io.IOException; import java.util. ...

  2. java String.split()函数的用法分析

    java String.split()函数的用法分析 栏目:Java基础 作者:admin 日期:2015-04-06 评论:0 点击: 3,195 次 在java.lang包中有String.spl ...

  3. Android使用JNI(从java调用本地函数)

    当编写一个混合有本地C代码和Java的应用程序时,需要使用Java本地接口(JNI)作为连接桥梁.JNI作为一个软件层和API,允许使用本地代码调用Java对象的方法,同时也允许在Java方法中调用本 ...

  4. 关于C++与Java中虚函数问题的读书笔记

    之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...

  5. 用JAVA写一个函数,功能例如以下: 随意给定一组数, 找出随意数相加之后的结果为35(随意设定)的情况

    用JAVA写一个函数.功能例如以下:随意给定一组数,比如{12,60,-8,99,15,35,17,18},找出随意数相加之后的结果为35(随意设定)的情况. 能够递归算法来解: package te ...

  6. java中main函数解析(转载)

    从写java至今,写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己,为什么要这么写,因为在c语言中就没有这样子的要 ...

  7. java的数学函数总结

    java的数学函数都放在java.lang这个包中,并且这些函数的方法在类Math中是作为static方法出现的,所以要引用一个特定的函数,只需将类Math和一个圆点写在要使用的方法前就好.如方法sq ...

  8. JAVA中字符串函数subString的用法小结

    本篇文章主要是对JAVA中字符串函数subString的用法进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 String str; str=str.substring(int begi ...

  9. Java中的函数对象

    初次听说java中的函数对象可能,比较的陌生.可以类比着来理解一下,人们常说java中没有了指针,殊不知,java中的对象引用就是指针,有时候我们说一个对象往往指的就是这个对象的引用,也就是说基本上把 ...

随机推荐

  1. 比较好用的php函数

    eval(); $b = 2;$c = "+";$d = 3;eval("\$a=$b$c$d;"); //字符串相加,取值 (加减乘除都行) str_repl ...

  2. ACM Arithmetic Expression

    Description Given N arithmetic expressions, can you tell whose result is closest to 9? Input Line 1: ...

  3. 【bzoj3160】万径人踪灭 FFT

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3160 我是一个傻叉 微笑脸 #include<bits/stdc++.h> #de ...

  4. IDictionary<TKey, TValue> vs. IDictionary

    Enumerating directly over an IDictionary<TKey,TValue>returns a sequence of  KeyValuePair struc ...

  5. 关于tag标签系统的实现

    实验室的项目,需要做对用户发布的主题进行打标签的功能,纠结甚久,实现思路如下: 一.数据库表的设计 1.tag表 create table qa_tag ( tag_id int primary ke ...

  6. Odoo 仓库扫码打包方案

        Odoo仓库扫码的设计,前提是操作人在PC上先做好分拣单,然后根据打印出来的分拣单去仓库进行扫码打包,默认的情况下,分拣在被确认的时候会自动保留库位中已经存在的库存(已经分配批次\序列号),而 ...

  7. html制作一个美观的搜索框

    一般情况下搜索栏就是form标签中的一个input标签. 如: <form> <input type="text" placeholder=" 搜索关键 ...

  8. js 原生 ajax 异步上传图片

    <script type="text/javascript"> function upload() { var file1 = document.getElementB ...

  9. linux笔记三-------根目录相关说明

    1. /bin   binary二进制文件,可执行程序文件          ls   su    pwd    cd          内部文件是一些指令信息 2. /sbin  super bin ...

  10. javascript事件有哪些?javascript的监听事件

    事件类型: 1.界面事件 onload:描述文档,图片,css已经frame,object加载完毕时触发,window.onload window.onload = function(){ //代表图 ...