Hadoop权威指南---map和reduce函数使用解析

目录

1、数据准备

2、  Java MapReduce 

2.1、map函数的实现

2.2、reduce函数的实现

2.3、负责运行MapReduce的代码

2.4、运行测试 

3、旧的和新的Java MapReduce API几个明显的区别

4、数据流和combiner函数 

4.1  数据流 

4.2  combiner函数 

4.3  Hadoop Streaming 

5、分布式存储数据需要解决的问题

6、关系型数据库和mapreduce的对比


总结:
1、在map输出结果的时候可以自定义结果的输出分区 ,然后再job中添加分区设置,启用分区,并且map输出分区的个数对应于reduce的个数。job.setPartitionerClass(ProvincePartitioner.class);//加入自定义分区,这个设置五个分区用于存储map的结果,需要注意的是map的结果存在本地磁盘而非HDFS;job.setNumReduceTasks(5);//设置reduce任务数目;

2、有几个reduce就会存在几个输出文件,reduce的输出是存在HDFS上的,保证结果的可靠性存储;
3、combiner函数的功能是为了减少数据在map的reduce之间的传输,把在reduce上进行的处理在不影响结果的情况下,提前移动到map端;在job中设置启用combiner功能:job.setCombinerClass(MaxTemperatureReducer.class);

1、数据准备

MapReduce任务过程分为两个处理阶段:map阶段和reduce阶段。每个阶段都以键值对作为输入和输出,其类型由程序员来选择。程序员还需要写两个函数:map函数和reduce 函数。这里map阶段的输入是NCDC原始数据。我们选择文本格式作为输入格式,将数据集的每一行作为文本输入。键是某一行起始位置相对于文件起始位置的偏移量,不过我们不需要这个信息,所以将其忽略。我们的map函数很简单。由于我们只对年份和气温属性感兴趣,所以只需要取出这两个字段数据。在本例中,map函数只是一个数据准备阶段,通过这种方式来准备数据,使reducer函数能够继续对它进行处理:即找出每年的最高气温。map函数还是一个比较适合去除已损记录的地方:此处,我们筛掉缺失的、可疑的或错误的气温数据。为了全面了解map 的工作方式,我们考虑以下输入数据的示例数据(考虑到篇幅,去除了一些未使用的列,并用省略号表示):

0067011990999991950051507004...9999999N9+00001+99999999999... 
0043011990999991950051512004...9999999N9+00221+99999999999... 
0043011990999991950051518004...9999999N9-00111+99999999999... 
0043012650999991949032412004...0500001N9+01111+99999999999... 
0043012650999991949032418004...0500001N9+00781+99999999999...
这些行以键/值对的方式作为map函数的输入: 
(0, 0067011990999991950051507004...9999999N9+00001+99999999999...) 
(106, 0043011990999991950051512004...9999999N9+00221+99999999999...) 
(212, 0043011990999991950051518004...9999999N9-00111+99999999999...) 
(318, 0043012650999991949032412004...0500001N9+01111+99999999999...) 
(424, 0043012650999991949032418004...0500001N9+00781+99999999999...)
键(key)是文件中的行偏移量,map函数并不需要这个信息,所以将其忽略。map函数的功能仅限于提取年份和气温信息(以粗体显示),并将它们作为输出(气温值已用整数表示): 
(1950, 0)
(1950, 22)
(1950, −11) 
(1949, 111) 
(1949, 78)
map函数的输出经由MapReduce框架处理后,最后发送到reduce函数。这个处理过程基于键来对键值对进行排序和分组。因此,在这一示例中,reduce函数看到的是如下输入: 
(1949, [111, 78]) 
(1950, [0, 22, −11])
每一年份后紧跟着一系列气温数据。reduce函数现在要做的是遍历整个列表并从中找出最大的读数:
(1949, 111) 
(1950, 22)
这是最终输出结果:每一年的全球最高气温记录。 
整个数据流如图2-1所示。在图的底部是Unix管线,用于模拟整个MapReduce的流程
  Hadoop权威指南---map和reduce函数使用解析_第1张图片
图2-1. MapReduce的逻辑数据流 

2、  Java MapReduce 

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

import java.io.IOException;

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

public class MaxTemperatureMapper 
  extends MapReduceBase implements Mapper {

  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) == '+') { // parseInt doesn't like leading plus signs
      airTemperature = Integer.parseInt(line.substring(88, 92));
    } else {
      airTemperature = Integer.parseInt(line.substring(87, 92));
    }
    String quality = line.substring(92, 93);
    if (airTemperature != MISSING && quality.matches("[01459]")) {
      context.write(new Text(year), new IntWritable(airTemperature));   输出
    }
  }
}

2.1、map函数的实现

这个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 类型中。只有气温数据不缺并且所对应质量代码显示为正确的气温读数时,这些数据才会被写入输出记录中。

2.2、reduce函数的实现

以类似方法用Reducer来定义reduce函数

import java.io.IOException;

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

public class MaxTemperatureReducer
  extends Reducer {
 
  @Override
  public void reduce(Text key, Iterable values,
      Context context)
      throws IOException, InterruptedException {
   
    int maxValue = Integer.MIN_VALUE;
    for (IntWritable value : values) {
      maxValue = Math.max(maxValue, value.get());
    }
    context.write(key, new IntWritable(maxValue));  输出
  }
}

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

2.3、负责运行MapReduce的代码

import java.io.IOException;
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.input.FileOutputFormat; 
import org.apache.hadoop.mapredduce.input.FileOutputFormat

public class MaxTemperature {

  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      System.err.println("Usage: MaxTemperature  ");
      System.exit(-1);
    }
   
    Job job = new Job();
    job.setJarByClass(MaxTemperature.class);  指定运行的作业类
    job.setJobName("Max temperature");       

    FileInputFormat.addInputPath(job, new Path(args[0]));   指定数据的位置
    FileOutputFormat.setOutputPath(job, new Path(args[1]));  指定结果的输出位置(如果已经存在报错)
   
    job.setMapperClass(MaxTemperatureMapper.class);       指定该job的map处理类
    job.setReducerClass(MaxTemperatureReducer.class);        指定该job的reduce处理类

    job.setOutputKeyClass(Text.class);              指定最终的输出key
    job.setOutputValueClass(IntWritable.class);     指定最终的输出value
   
    System.exit(job.waitForCompletion(true) ? 0 : 1);  提交作业并等待执行完成
  }
}


Job对象指定作业执行规范。我们可以用它来控制整个作业的运行。我们在Hadoop 集群上运行这个作业时,要把代码打包成一个JAR文件(Hadoop在集群上发布这个文件)。不必明确指定JAR文件的名称,在Job对象的setJarByClass()方法中传递一个类即可,Hadoop利用这个类来查找包含它的JAR文件,进而找到相关的JAR文件。 构造Job对象之后,需要指定输入和输出数据的路径。调用 FileInputFormat类的静态方法addInputPath()来定义输入数据的路径,这个路径可以是单个的文件、一个目录(此时,将目录下所有文件当作输入)或符合特定文件模式的一系列文件。由函数名可知,可以多次调用addInputPath()来实现多路径的输入。调用FileOutputFormat 类中的静态方法 setOutputPath()来指定输出路径(只能有一个输出路径)。这个方法指定的是reduce 函数输出文件的写入目录。在运行作业前该目录是不应该存在的,否则Hadoop 会报错并拒绝运行作业。这种预防措施的目的是防止数据丢失(长时间运行的作业如果结果被意外覆盖,肯定是非常恼人的)。接着,通过setMapperClass()和setReducerClass()指定map类型和reduce类型。setOutputKeyClass()和setOutputValueClass()控制map和reduce函数的输出类型,正如本例所示,这两个输出类型一般都是相同的。如果不同,则通过setMapOutputKeyClass()和setMapOutputValueClass()来设置map函数的输出类型。输入的类型通过InputFormat类来控制,我们的例子中没有设置,因为使用的是默认的TextInputFormat(文本输入格式)。

在设置定义map 和reduce 函数的类之后,可以开始运行作业。Job中的waitForCompletion()方法提交作业并等待执行完成。该方法中的布尔参数是个详细标识,所以作业会把进度写到控制台。waitForCompletion()方法返回一个布尔值,表示执行的成 (true)败(false),这个布尔值被转换成程序的退出代码0或者1。

2.4、运行测试 

首先,以独立(本机)模式安装Hadoop,详细说明请参见附录A。在这种模式下,Hadoop在本地文件系统上运行作业程序

以前面讨过的5行采样数据为例来测试MapReduce作业(考虑到篇幅,这里对输出稍有修改):

% export HADOOP_CLASSPATH=hadoop-examples.jar
% hadoop MaxTemperature input/ncdc/sample.txt output

12/02/04 11:50:41 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
12/02/04 11:50:41 WARN mapred.JobClient: Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
12/02/04 11:50:41 INFO input.FileInputFormat: Total input paths to process : 1
12/02/04 11:50:41 INFO mapred.JobClient: Running job: job_local_0001
12/02/04 11:50:41 INFO mapred.Task:  Using ResourceCalculatorPlugin : null
12/02/04 11:50:41 INFO mapred.MapTask: io.sort.mb = 100
12/02/04 11:50:42 INFO mapred.MapTask: data buffer = 79691776/99614720
12/02/04 11:50:42 INFO mapred.MapTask: record buffer = 262144/327680
12/02/04 11:50:42 INFO mapred.MapTask: Starting flush of map output
12/02/04 11:50:42 INFO mapred.MapTask: Finished spill 0
12/02/04 11:50:42 INFO mapred.Task: Task:attempt_local_0001_m_000000_0 is done. And is in the process of commiting
12/02/04 11:50:42 INFO mapred.JobClient:  map 0% reduce 0%
12/02/04 11:50:44 INFO mapred.LocalJobRunner:
12/02/04 11:50:44 INFO mapred.Task: Task 'attempt_local_0001_m_000000_0' done.
12/02/04 11:50:44 INFO mapred.Task:  Using ResourceCalculatorPlugin : null
12/02/04 11:50:44 INFO mapred.LocalJobRunner:
12/02/04 11:50:44 INFO mapred.Merger: Merging 1 sorted segments
12/02/04 11:50:44 INFO mapred.Merger: Down to the last merge-pass, with 1 segments left of total size: 57 bytes
12/02/04 11:50:44 INFO mapred.LocalJobRunner:
12/02/04 11:50:45 INFO mapred.Task: Task:attempt_local_0001_r_000000_0 is done. And is in the process of commiting
12/02/04 11:50:45 INFO mapred.LocalJobRunner:
12/02/04 11:50:45 INFO mapred.Task: Task attempt_local_0001_r_000000_0 is allowed to commit now
12/02/04 11:50:45 INFO output.FileOutputCommitter: Saved output of task 'attempt_local_0001_r_000000_0' to output
12/02/04 11:50:45 INFO mapred.JobClient:  map 100% reduce 0%
12/02/04 11:50:47 INFO mapred.LocalJobRunner: reduce > reduce
12/02/04 11:50:47 INFO mapred.Task: Task 'attempt_local_0001_r_000000_0' done.
12/02/04 11:50:48 INFO mapred.JobClient:    map 100% reduce 100%
12/02/04 11:50:48 INFO mapred.JobClient:    Job complete: job_local_0001
12/02/04 11:50:48 INFO mapred.JobClient:     Counters: 17
12/02/04 11:50:48 INFO mapred.JobClient:     File Output Format Counters
12/02/04 11:50:48 INFO mapred.JobClient:      Bytes Written=29
12/02/04 11:50:48 INFO mapred.JobClient:       FileSystemCounters
12/02/04 11:50:48 INFO mapred.JobClient:      FILE_BYTES_READ=357503
12/02/04 11:50:48 INFO mapred.JobClient:      FILE_BYTES_WRITTEN=425817
12/02/04 11:50:48 INFO mapred.JobClient:       File Input Format Counters
12/02/04 11:50:48 INFO mapred.JobClient:     Bytes Read=529
12/02/04 11:50:48 INFO mapred.JobClient:       Map-Reduce Framework
12/02/04 11:50:48 INFO mapred.JobClient:     Map output materialized bytes=61
12/02/04 11:50:48 INFO mapred.JobClient:      Map input records=5
12/02/04 11:50:48 INFO mapred.JobClient:      Reduce shuffle bytes=0
12/02/04 11:50:48 INFO mapred.JobClient:      Spilled Records=10
12/02/04 11:50:48 INFO mapred.JobClient:     Map output bytes=45
12/02/04 11:50:48 INFO mapred.JobClient:     Total committed heap usage (bytes)=369238016
12/02/04 11:50:48 INFO mapred.JobClient:      SPLIT_RAW_BYTES=129
12/02/04 11:50:48 INFO mapred.JobClient:      Combine input records=0
12/02/04 11:50:48 INFO mapred.JobClient:      Reduce input records=5
12/02/04 11:50:48 INFO mapred.JobClient:      Reduce input groups=2
12/02/04 11:50:48 INFO mapred.JobClient:      Combine output records=0
12/02/04 11:50:48 INFO mapred.JobClient:      Reduce output records=2
12/02/04 11:50:48 INFO mapred.JobClient:      Map output records=5


如果调用hadoop命令的第一个参数是类名,Hadoop就会启动一个JVM(Java虚拟机)来运行这个类。使用hadoop命令运行作业比直接使用Java命令来运行更方便,因为前者将Hadoop库文件(及其依赖关系)路径加入到类路径参数中,同时也能获得Hadoop的配置文件。需要定义一个 HADOOP_CLASSPATH 环境变量用于添加应用程序类的路径,然后由Hadoop 脚本来执行相关操作。 以本地(独立)模式运行时,本书中所有程序均假设按照这种方式来设置HADOOP_CLASSPATH。命令的运行需要在范例代码所在的文件夹下进行。

运行作业所得到的输出提供了一些有用的信息。例如,我们可以看到,这个作业有指定的标识,即job_local_0001,并且执行了一个map 任务和一个reduce 任务(使用attempt_local_0001_m_000000_0和attempt_ local_0001_r_000000_0两个ID)。在调试MapReduce作业时,知道作业ID和任务ID 是非常有用的。 输出的最后一部分,以Counters为标题,显示Hadoop 上运行的每个作业的一些统计信息。这些信息对检查数据是否按照预期进行处理非常有用。
例如,我们查看系统输出的记录信息可知:5个map输入产生了5个map输出,然后5个reduce 输入产生2个reduce 输出。 
输出数据写入output目录,其中每个reducer都有一个输出文件。我们的例子中只有一个 reducer,所以只能找到一个名为part-00000的文件: 
% cat output/part-r-00000 
1949    111 
1950    22
这个结果和我们之前手动寻找的结果一样。我们把这个结果解释为1949年的最高气温记录为11.1℃,而1950 年为2.2℃。 

3、旧的和新的Java MapReduce API几个明显的区别


1)、新API 倾向于使用虚类,而不是接口,因为更有利于扩展。这意味着用不着修改类的实现,即可在虚类中添加一个方法(即默认的实现)。在旧API中使用Mapper和Reducer接口,而在新API 中使用虚类。 
2)、新API放在org.apache.hadoop.mapreduce包(和子包)中。之前版本的API依旧放在org.apache.hadoop.mapred中。
3)、新API充分使用上下文对象,使用户代码能与MapReduce系统通信。例如,新的Context基本统一了旧API中的JobConf、OutputCollector和Reporter的功能。
4)、键/值对记录在这两类API中都被推给mapper和reducer,但除此之外,新的API 通过重写run()方法允许mapper和reducer控制执行流程。
例如,既可以批处理记录,也可以在处理完所有的记录之前停止。在旧API中可以通过写MapRunnable类在mapper中实现上述功能,但是在reducer中没有对等的实现。
5)、新的API中作业控制由Job类实现,而非旧API中的JobClient类,新的API中删除了JobClient类。
6)、新增的API实现了配置的统一。旧API 通过一个特殊的JobConf 对象配置作业,该对象是Hadoop配置对象的一个扩展。在新API 中,作业的配置由Configuration(或许通过Job类中的一些辅助方法)来完成。
7)、输出文件的命名方式稍有不同。在旧的API中map和reduce的输出被统一命名为part-nnmm,但是在新API中map的输出文件名为part-m-nnnnn,
而reduce的输出文件名为part-r-nnnnn(其中nnnnn是从0开始的表示分块序号的整数)。
8)、新API中的用户重载函数被声明为抛出异常java.lang.InterruptedException。这意味着可以用代码来实现中断响应,从而使该框架在必要时可以优雅地取消需长时间运行的作业。
9)、在新的API中,reduce()传递的值是java.lang.Iterable类型的,而非java.lang.Iterator类型(旧API中传递该类型的值)。这一改变使我们更容易通过Java的for-each循环结构来来迭代这些值。

4、数据流和combiner函数 

4.1  数据流 

首先定义一些术语。MapReduce作业(job) 是客户端需要执行的一个工作单元:它包括输入数据、MapReduce程序和配置信息。Hadoop将作业分成若干个小任务 (task)来执行,其中包括两类任务:map任务和reduce任务。

Hadoop权威指南---map和reduce函数使用解析_第2张图片

Hadoop权威指南---map和reduce函数使用解析_第3张图片

Hadoop权威指南---map和reduce函数使用解析_第4张图片

Hadoop权威指南---map和reduce函数使用解析_第5张图片

Hadoop权威指南---map和reduce函数使用解析_第6张图片

Hadoop权威指南---map和reduce函数使用解析_第7张图片

Hadoop权威指南---map和reduce函数使用解析_第8张图片

 Hadoop权威指南---map和reduce函数使用解析_第9张图片

Hadoop权威指南---map和reduce函数使用解析_第10张图片

4.2  combiner函数 

集群上的可用带宽限制了MapReduce作业的数量,因此尽量避免map和reduce任务之间的数据传输是有利的。Hadoop允许用户针对map任务的输出指定一个combiner(就像mapper和reducer一样)——combiner函数的输出作为reduce函数的输入。由于combiner属于优化方案,所以Hadoop无法确定要对map任务输出记录调用多少次combiner (如果需要)。换而言之,不管调用combiner多少次,0次、1次或多次,reducer的输出结果都是一样的。

combiner的规则制约着可用的函数类型。这里最好用一个例子来说明。还是假设以前计算最高气温的例子,1950年的读数由两个map任务处理(因为它们在不同的分片中)。假设第一个map 的输出如下:

(1950, 0) 
(1950, 20) 
(1950, 10)
第二个map的输出如下: 
(1950, 25) 
(1950, 15)
  
图2-5. 无reduce任务的MapReduce数据流 
reduce函数被调用时,输入如下: 
(1950, [0, 20, 10, 25, 15])
因为25为该列数据中最大的,所以它的输出如下: 
(1950, 25)
我们可以像使用reduce函数那样,使用combiner找出每个map任务输出结果中的最高气温。如此一来,reduce函数调用时将被传入以下数据: 
(1950, [20, 25]) 
reduce输出的结果和以前一样。更简单地说,我们可以通过下面的表达式来说明气温数值的函数调用:
max(0, 20, 10, 25, 15) = max(max(0, 20, 10), max(25, 15)) = max(20, 25) = 25 
并非所有函数都具有该属性。[ 有此属性的函数叫commutative和associative。有时也将它们称为distributive,比如在Gray等人1995年发表的论文“Data Cube: A Relational Aggregation Operatior Generalizing Groupby, Cross-Tab, and Sub-Totals”中。]例如,如果我们计算平均气温,就不能用平均数作为combiner,因为 
mean(0, 20, 10, 25, 15) = 14 
但是combiner不能取代reduce函数: 
mean(mean(0, 20, 10), mean(25, 15)) = mean(10, 20) = 15 
为什么呢?我们仍然需要reduce函数来处理不同map输出中具有相同键的记录。但它能有效减少mapper和reducer之间的数据传输量,在MapReduce作业中使用combiner函数需要慎重考虑。 
指定一个combiner 
让我们回到Java MapReduce 程序,combiner是通过Reducer类来定义的,并且在这个例子中,它的实现与MaxTemperatureReducer中的reduce函数相同。唯一的改动是在Job中设置combiner类(参见范例2-7)。 

使用combiner快速找出最高气温

public class MaxTemperatureWithCombiner {
  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      System.err.println("Usage: MaxTemperatureWithCombiner  " +
          "");
      System.exit(-1);
    }
   
    Job job = new Job();
    job.setJarByClass(MaxTemperatureWithCombiner.class);
    job.setJobName("Max temperature");

    FileInputFormat.addInputPath(job, new Path(args[0]));
    FileOutputFormat.setOutputPath(job, new Path(args[1]));
   
    job.setMapperClass(MaxTemperatureMapper.class);
    job.setCombinerClass(MaxTemperatureReducer.class);
    job.setReducerClass(MaxTemperatureReducer.class);
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(IntWritable.class);
   
    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}

 

4.3  Hadoop Streaming 

Hadoop提供了MapReduce的API,允许你使用非Java的其他语言来写自己的map和reduce函数。HadoopStreaming使用Unix标准流作为Hadoop和应用程序之间的接口,所以我们可以使用任何编程语言通过标准输入/输出来写MapReduce程序。

Streaming天生适合用于文本处理。map的输入数据通过标准输入流传递给map函数,并且是一行一行地传输,最后将结果行写到标准输出。map输出的键/值对是以一个制表符分隔的行,并且写入标准输出reduce 函数的输入格式与之相同(通过制表符来分隔的键/值对)并通过标准输入流进行传输。reduce函数从标准输入流中读取输入行,该输入已由Hadoop框架根据键排过序,最后将结果写入标准输出。

下面使用Streaming来重写按年份查找最高气温的MapReduce程序。


Python版本 
Streaming支持任何可以从标准输入读取和写入到标准输出中的编程语言,因此对于更熟悉Python的读者,下面提供了同一个例子的Python 版本。map脚本参见范例2-10,reduce脚本参见范例2-11。

范例2-10. 用于查找最高气温的map函数(python版)

#!/usr/bin/env python

import re 
import sys

for line in sys.stdin:   
  val = line.strip()   
  (year, temp, q) = (val[15:19], val[87:92], val[92:93])   
  if (temp != "+9999" and re.match("[01459]", q)):     
    print "%s\t%s" % (year, temp)


范例2-11. 用于查找最高气温的reduce函数(python版) 

#!/usr/bin/env python

import sys

(last_key, max_val) = (None, -sys.maxint)
for line in sys.stdin:   
  (key, val) = line.strip().split("\t")   
  if last_key and last_key != key:     
    print "%s\t%s" % (last_key, max_val)     
    (last_key, max_val) = (key, int(val))   
  else:     
    (last_key, max_val) = (key, max(max_val, int(val)))
if last_key:   
  print "%s\t%s" % (last_key, max_val)


我们可以像测试Ruby程序那样测试程序并运行作业。例如,可以像下面这样运行测试: 
% cat input/ncdc/sample.txt | ch02/src/main/python/max_temperature_map.py | \   
  sort | ch02/src/main/python/max_temperature_reduce.py 
1949    111 
1950    22

5、分布式存储数据需要解决的问题

Hadoop权威指南---map和reduce函数使用解析_第11张图片

6、关系型数据库和mapreduce的对比

Hadoop权威指南---map和reduce函数使用解析_第12张图片

注意:区分写时模式和读时模式

Hadoop权威指南---map和reduce函数使用解析_第13张图片

 


参考:

《Hadoop权威指南.大数据的存储与分析.第4版》--第1章 初识Hadoop 和第2章 关于MapReduce 

https://www.csdn.net/article/2014-11-05/2822487#2.1

你可能感兴趣的:(读书笔记,Hadoop,MapReduce)