例2-8中的map函数是用ruby来写的。
例2-8:用于查找最高气温的map函数(ruby版)
1. #!/usr/bin/env ruby
2.
3. STDIN.each_line do |line|
4. val = line
5. year, temp, q = val[15,4], val[87,5], val[92,1]
6. puts "#{year}\t#{temp}" if (temp != "+9999" && q =~ /[01459]/)
7. end
程序通过执行STDIN(IO类型的一个全局常量)中的每行,不断从标准输入中反复查找。它把相关的字段从每行中取出,如果气温有效,就过一个tab字符\t把年份和气温通隔开,然后输入标准输出(使用puts)。
注意:指出流和Java MapReduce API 之间的差异是十分值得的。 Java的API是主要面向一次处理一个map函数的记录。该框架调用Mapper的map()方法来处理输入中的每条记录,然而map程序可以决定如何处理输入流,例如,它可以轻松地读取和同一时间处理多行,因为它控制着多行读取。用户的Java map实现是压栈记录,但它仍可以考虑处理多行,具体做法是将mapper中实例变量中之前的行汇聚在一起。在这种情况下,需要实现close()方法,以便了解最后的记录何时被读取,从而完成对最后一组记录行的处理。
由于该脚本只运行在标准输入和输出上,所以只需使用Unix管道而不使用Hadoop来进行测试,这是不具有说服力的:
1. % cat input/ncdc/sample.txt | src/main/ch02/ruby/max_
2.
3. temperature_map.rb
4. 1950 +0000
5. 1950 +0022
6. 1950 -0011
7. 1949 +0111
8. 1949 +0078
例2-9显示的reduce函数稍微复杂一些。
例2-9:用于查找最高气温的Reduce函数(Ruby版本)
1. #!/usr/bin/env ruby
2.
3. last_key, max_val = nil, 0
4. STDIN.each_line do |line|
5. key, val = line.split("\t")
6. if last_key && last_key != key
7. puts "#{last_key}\t#{max_val}"
8. last_key, max_val = key, val.to_i
9. else
10. last_key, max_val = key, [max_val, val.to_i].max
11. end
12. end
13. puts "#{last_key}\t#{max_val}" if last_key
同样,程序遍历标准输入中的行,但是当我们处理每组键时,我们要存储一些状态。在这种情况下,这个键是气象站的标识符,我们把看到的最后一个键和迄今为止见到的最高气温存储到那个键组中。MapReduce框架确保键是有序的,以便让我们知道,如果一个键与其上一个键不同,可将其它移入一个新的键组。相比之下,Java API则提供每一个键组的迭代器,我们只能在流中使用程序来找到键组的边界。
我们从每行中取出键和值,随后,如果刚刚完成一组键(last_key&last_key =键),则在将新值更新为最高气温之前,写入键和该组的最高气温,它们由一个制表符来分隔。如果我们没有结束一个组,只能更新当前键的最高气温。
程序的最后一行保证了输入的最后一组键会有一行输出。
现在可以用UNIX管线(来模拟整个MapReduce的管线,它与图2-1显示的Unix 管线是相同的)。
1. % cat input/ncdc/sample.txt | src/main/ch02
/ruby/max_temperature_map.rb | \
2. sort | src/main/ch02/ruby/max_temperature_reduce.rb
3. 1949 111
4. 1950 22
输出结果和Java 程序一样,所以下一步是用Hadoop来运行它。
Hadoop命令不支持Streaming函数,因此,我们需要指定JAR文件流与jar选项。流程序的选项指定了输入和输出路径选项,map和reudce脚本,如下所示:
1. % hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-
2. streaming.jar \
3. -input input/ncdc/sample.txt \
4. -output output \
5. -mapper src/main/ch02/ruby/max_temperature_map.rb \
6. -reducer src/main/ch02/ruby/max_temperature_reduce.rb
在一个集群上运行一个庞大的数据集时,要使用-combiner选项来设置combiner。
从0.21.0版开始,combiner可以是任何一个流命令。对于早期版本的combiner,只能用Java来编写,所以作为变通的方法,一般都在mapper中手动合并,从而避开Java语言。在这种情况下,我们可以把mapper改成管线:
1. % hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-
2. streaming.jar \
3. -input input/ncdc/all \
4. -output output \
5. -mapper "ch02/ruby/max_temperature_map.rb | sort |
6. ch02/ruby/max_temperature_reduce.rb" \
7. -reducer src/main/ch02/ruby/max_temperature_reduce.rb \
8. -file src/main/ch02/ruby/max_temperature_map.rb \
9. -file src/main/ch02/ruby/max_temperature_reduce.rb
还要注意-file的使用,在集群上运行流程序把脚本传输到集群上时,可使用此选项。
例2-8:用于查找最高气温的map函数(ruby版)
1. #!/usr/bin/env ruby
2.
3. STDIN.each_line do |line|
4. val = line
5. year, temp, q = val[15,4], val[87,5], val[92,1]
6. puts "#{year}\t#{temp}" if (temp != "+9999" && q =~ /[01459]/)
7. end
程序通过执行STDIN(IO类型的一个全局常量)中的每行,不断从标准输入中反复查找。它把相关的字段从每行中取出,如果气温有效,就过一个tab字符\t把年份和气温通隔开,然后输入标准输出(使用puts)。
注意:指出流和Java MapReduce API 之间的差异是十分值得的。 Java的API是主要面向一次处理一个map函数的记录。该框架调用Mapper的map()方法来处理输入中的每条记录,然而map程序可以决定如何处理输入流,例如,它可以轻松地读取和同一时间处理多行,因为它控制着多行读取。用户的Java map实现是压栈记录,但它仍可以考虑处理多行,具体做法是将mapper中实例变量中之前的行汇聚在一起。在这种情况下,需要实现close()方法,以便了解最后的记录何时被读取,从而完成对最后一组记录行的处理。
由于该脚本只运行在标准输入和输出上,所以只需使用Unix管道而不使用Hadoop来进行测试,这是不具有说服力的:
1. % cat input/ncdc/sample.txt | src/main/ch02/ruby/max_
2.
3. temperature_map.rb
4. 1950 +0000
5. 1950 +0022
6. 1950 -0011
7. 1949 +0111
8. 1949 +0078
例2-9显示的reduce函数稍微复杂一些。
例2-9:用于查找最高气温的Reduce函数(Ruby版本)
1. #!/usr/bin/env ruby
2.
3. last_key, max_val = nil, 0
4. STDIN.each_line do |line|
5. key, val = line.split("\t")
6. if last_key && last_key != key
7. puts "#{last_key}\t#{max_val}"
8. last_key, max_val = key, val.to_i
9. else
10. last_key, max_val = key, [max_val, val.to_i].max
11. end
12. end
13. puts "#{last_key}\t#{max_val}" if last_key
同样,程序遍历标准输入中的行,但是当我们处理每组键时,我们要存储一些状态。在这种情况下,这个键是气象站的标识符,我们把看到的最后一个键和迄今为止见到的最高气温存储到那个键组中。MapReduce框架确保键是有序的,以便让我们知道,如果一个键与其上一个键不同,可将其它移入一个新的键组。相比之下,Java API则提供每一个键组的迭代器,我们只能在流中使用程序来找到键组的边界。
我们从每行中取出键和值,随后,如果刚刚完成一组键(last_key&last_key =键),则在将新值更新为最高气温之前,写入键和该组的最高气温,它们由一个制表符来分隔。如果我们没有结束一个组,只能更新当前键的最高气温。
程序的最后一行保证了输入的最后一组键会有一行输出。
现在可以用UNIX管线(来模拟整个MapReduce的管线,它与图2-1显示的Unix 管线是相同的)。
1. % cat input/ncdc/sample.txt | src/main/ch02
/ruby/max_temperature_map.rb | \
2. sort | src/main/ch02/ruby/max_temperature_reduce.rb
3. 1949 111
4. 1950 22
输出结果和Java 程序一样,所以下一步是用Hadoop来运行它。
Hadoop命令不支持Streaming函数,因此,我们需要指定JAR文件流与jar选项。流程序的选项指定了输入和输出路径选项,map和reudce脚本,如下所示:
1. % hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-
2. streaming.jar \
3. -input input/ncdc/sample.txt \
4. -output output \
5. -mapper src/main/ch02/ruby/max_temperature_map.rb \
6. -reducer src/main/ch02/ruby/max_temperature_reduce.rb
在一个集群上运行一个庞大的数据集时,要使用-combiner选项来设置combiner。
从0.21.0版开始,combiner可以是任何一个流命令。对于早期版本的combiner,只能用Java来编写,所以作为变通的方法,一般都在mapper中手动合并,从而避开Java语言。在这种情况下,我们可以把mapper改成管线:
1. % hadoop jar $HADOOP_INSTALL/contrib/streaming/hadoop-*-
2. streaming.jar \
3. -input input/ncdc/all \
4. -output output \
5. -mapper "ch02/ruby/max_temperature_map.rb | sort |
6. ch02/ruby/max_temperature_reduce.rb" \
7. -reducer src/main/ch02/ruby/max_temperature_reduce.rb \
8. -file src/main/ch02/ruby/max_temperature_map.rb \
9. -file src/main/ch02/ruby/max_temperature_reduce.rb
还要注意-file的使用,在集群上运行流程序把脚本传输到集群上时,可使用此选项。
本文介绍了一个使用Ruby编写的MapReduce示例程序,旨在找出最高气温记录。该程序包括两个部分:Map函数用于处理输入数据并提取年份与气温信息;Reduce函数则负责聚合相同年份的数据并确定每年的最高气温。
914

被折叠的 条评论
为什么被折叠?



