一个基于Hadoop Streaming + Python的MapReduce例子
参见《Hadoop权威指南(第3版)》第二章
准备工作:
Hadoop2.7.2版本安装
python环境安装
数据准备:这里用的是NCDC的1901 1902两年的数据(其他的数据大家可以FTP下载下来)
实验目的:
通过Hadoop Streaming + Python统计每年最高气温
背景知识介绍:
Hadoop Streaming使用UNIX标准流作为Hadoop和应用程序之间的接口,因此任何语言都可以通过标准的输入/输出写MapReduce程序。后面会在程序的注释中说明数据是如何在Map和Reduce任务中流动的。
1. 上传数据到hdfs
我们将1901和1902两个文件上传到HDFS的/ncdc目录下
如果没有该目录,首先创建:
hdfs dfs -mkdir /ncdc
上传1901 1902两个文件到hdfs的/ncdc
hdfs dfs -put 1901 1902 /ncdc
2. 编写map和reduce程序
注意,map函数的输入就是数据文件,map函数从标准输入中获取数据,因此一般按行处理数据。以NCDC的数据为例子,每一行的格式如下:
0029029070999991901010106004+64333+023450FM-12+000599999V0202701N015919999999N0000001N9-00781+99999102001ADDGF108991999999999999999999
其中,第15到第19个字符表示年份,第87到第92个字符表示温度。
因此,map程序如下:
输入:NCDC数据
输出:年份+气温
#!/usr/bin/env python
import sys
for line in sys.stdin:
year, temp = line[15:19], line[87:92]
if temp != '+9999':
print('%s\t%s' % (year, temp))
注意:
(1)头部必须添加,否则Hadoop不知道用什么去执行任务
<span style="font-family:Microsoft YaHei;">#!/usr/bin/env python</span>
(2)temp != '+9999'
此行对非法处理做过滤
(3)最后一行的输出就是reduce的输入,key和value之间用\t分割,由此可知,reduce的输入也是标准输入,中间的过程由hadoop控制
reduce程序将会获取同一个年份中的最高温度。
输入:年份+气温
输出:年份+最高气温
#!/usr/bin/env python
import sys
current_year=None
current_temp=-sys.maxint
for line in sys.stdin:
year, temp = line.split()
temp=int(temp)
if year == current_year:
if current_temp < temp:
current_temp = temp
else:
if current_year:
print("%s\t%s" % (current_year, current_temp))
current_year=year
current_temp=temp
if current_year:
print("%s\t%s" % (current_year, current_temp))
代码有点多,我们一步一步分析:
(1)首先需要说明的是,reduce的输入是map的输出,而且输出已经被MapReduce框架根据键值做了排序,因此reduce的输入是按年份排序的 年份+气温。
(2)我们需要自己找到两个不同键值的交汇点,然后做相应的处理,因此我们使用了current_year和current_temp作为当前正在处理的年份和最高气温,如果下一条数据的年份year与current_year相同,证明还是同一个年份,这个时候需要判断该数据的温度temp是否大于current_temp,如果大于则current_temp=temp。如果year与current_year不同,证明到了下一个年份,这个时候就要输出当前的年份和最高温度current_year和current_temp,这里请大家再次注意,因为reduce的输入是按键值排序的,因此保证了此处的输出就是当前年份的最高温度。同时,要把current_year设置为year,将current_temp设置为temp
(3)注意最后两行代码,因为最后一个年份不会再出现year!=current_year的情况,因此需要最后两行,来把最后一个年份的最高温度输出出来,第一次看代码的时候有点晕,注意一下
3. 执行
(1)清理上次执行的结果(假定结果放在了/output/ncdc目录下)
hdfs dfs -rm -r /output/ncdc
(2)执行
hadoop jar hadoop/hadoop-2.7.3/share/hadoop/tools/lib/hadoop-streaming-2.7.3.jar
-files python/ncdc/mapper.py,python/ncdc/reducer.py
-input /ncdc/
-output /output/ncdc
-mapper mapper.py
-reducer reducer.py
注意参数-files,之前版本参数为-file,一次指定一个文件,现在改为了-files,指定多个需要发布到mapreduce执行环境的文件,不同文件之间用,分割。
-mapper 指定map处理程序,这里直接写文件名称即可
-reducer 指定reduce处理程序,这里直接写文件名称即可
(3)查看执行结果
hdfs dfs -cat /output/ncdc/part-00000
结果如下:
1901 317
1902 244
4. 权威指南中提到了可以考虑使用Dumbo框架作为Streaming的替代方案。给一篇参考文献:
http://www.oschina.net/translate/a-guide-to-python-frameworks-for-hadoop