1.概述

Hadoop Streaming提供了一个便于进行MapReduce编程的工具包,使用它可以基于一些可执行命令、脚本语言或其他编程语言来实现Mapper和 Reducer,从而充分利用Hadoop并行计算框架的优势和能力,来处理大数据。需要注意的是,Streaming方式是基于Unix系统的标准输入 输出来进行MapReduce Job的运行,它区别与Pipes的地方主要是通信协议,Pipes使用的是Socket通信,是对使用C++语言来实现MapReduce Job并通过Socket通信来与Hadopp平台通信,完成Job的执行。任何支持标准输入输出特性的编程语言都可以使用Streaming方式来实现MapReduce Job,基本原理就是输入从Unix系统标准输入,输出使用Unix系统的标准输出。

2.Hadoop Streaming原理

mapper和reducer会从标准输入中读取用户数据,一行一行处理后发送给标准输出。Streaming工具会创建MapReduce作业,发送给各个tasktracker,同时监控整个作业的执行过程。

如果一个文件(可执行或者脚本)作为mapper,mapper初始化时,每一个mapper任务会把该文件作为一个单独进程启动,mapper任 务运行时,它把输入切分成行并把每一行提供给可执行文件进程的标准输入。 同时,mapper收集可执行文件进程标准输出的内容,并把收到的每一行内容转化成key/value对,作为mapper的输出。 默认情况下,一行中第一个tab之前的部分作为key,之后的(不包括tab)作为value如果没有tab,整行作为key值,value值为null。

对于reducer,类似。以上是Map/Reduce框架和streaming mapper/reducer之间的基本通信协议。

3.Hadoop Streaming用法

Usage: $HADOOP_HOME/bin/hadoop jar \

$HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.7.0.jar

options:

  (1)-input:输入文件路径

  (2)-output:输出文件路径

  (3)-mapper:用户自己写的mapper程序,可以是可执行文件或者脚本

  (4)-reducer:用户自己写的reducer程序,可以是可执行文件或者脚本

  (5)-file:打包文件到提交的作业中,可以是mapper或者reducer要用的输入文件,如配置文件,字典等。

  (6)-partitioner:用户自定义的partitioner程序

  (7)-combiner:用户自定义的combiner程序(必须用java实现)

  (8)-D:作业的一些属性(以前用的是-jonconf),具体有:
1)mapred.map.tasks:map task数目
2)mapred.reduce.tasks:reduce task数目
3)stream.map.input.field.separator/stream.map.output.field.separator: map task输入/输出数据的分隔符,默认均为\t。
4)stream.num.map.output.key.fields:指定map task输出记录中key所占的域数目
5)stream.reduce.input.field.separator/stream.reduce.output.field.separator:reduce task输入/输出数据的分隔符,默认均为\t。
6)stream.num.reduce.output.key.fields:指定reduce task输出记录中key所占的域数目

另外,Hadoop本身还自带一些好用的Mapper和Reducer:

4.使用示例

使用Python编写MapReduce代码的技巧就在于我们使用了 HadoopStreaming 来帮助我们在Map 和 Reduce间传递数据通过STDIN (标准输入)和STDOUT (标准输出).我们仅仅使用Python的sys.stdin来输入数据,使用sys.stdout输出数据,这样做是因为 HadoopStreaming会帮我们办好其他事。这是真的,别不相信!

举例

将下列的代码保存在/usr/local/hadoop/mapper.py中,他将从STDIN读取数据并将单词成行分隔开,生成一个列表映射单词与发生次数的关系:注意:要确保这个脚本有足够权限(chmod +x mapper.py)。

#!/usr/bin/env python  

import sys  

# input comes from STDIN (standard input)
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()
    # split the line into words
    words = line.split()
    # increase counters
    for word in words:
        # write the results to STDOUT (standard output);
        # what we output here will be the input for the
        # Reduce step, i.e. the input for reducer.py
        #
        # tab-delimited; the trivial word count is 1
        print '%s\t%s' % (word, 1) 

将代码存储在/usr/local/hadoop/reducer.py 中,这个脚本的作用是从mapper.py 的STDIN中读取结果,然后计算每个单词出现次数的总和,并输出结果到STDOUT。同样,要注意脚本权限:chmod +x reducer.py

#!/usr/bin/env python  

from operator import itemgetter
import sys  

current_word = None
current_count = 0
word = None  

# input comes from STDIN
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()  

    # parse the input we got from mapper.py
    word, count = line.split('\t', 1)  

    # convert count (currently a string) to int
    try:
        count = int(count)
    except ValueError:
        # count was not a number, so silently
        # ignore/discard this line
        continue  

    # this IF-switch only works because Hadoop sorts map output
    # by key (here: word) before it is passed to the reducer
    if current_word == word:
        current_count += count
    else:
        if current_word:
            # write result to STDOUT
            print '%s\t%s' % (current_word, current_count)
        current_count = count
        current_word = word  

# do not forget to output the last word if needed!
if current_word == word:
    print '%s\t%s' % (current_word, current_count) 

测试结果:

hadoop@derekUbun:/usr/local/hadoop$ echo "foo foo quux labs foo bar quux" | ./mapper.py
foo      1
foo      1
quux     1
labs     1
foo      1
bar      1
quux     1
hadoop@derekUbun:/usr/local/hadoop$ echo "foo foo quux labs foo bar quux" |./mapper.py | sort |./reducer.py
bar     1
foo     3
labs    1
quux    2 

实例

需求:这里面只是个小练习,没有多高深,简单的不能再简单,只是一个小实例,做个抛砖的作用。

写一个mapreduce streaming程序(可使用任意语言,这里我们用python),将数据转换成“key=value”的格式,其中,key包括“ip”、“time”、“path”三个,

比如,175.44.30.93 - - [29/Sep/2013:00:10:16 +0800] "GET /structure/heap/ HTTP/1.1" 200 22539 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1;)"

转化为:ip=175.44.30.93|time=29/Sep/2013:00:10:16|path=/structure/heap/ 其中,不同key/value之间用“|”分割。

具体步骤:

1.将日志文件上传到hdfs上 hadoop fs -put 文件 目的地

2.编程程序,这个比较简单,我觉得只用mapper就能实现,我就只写了一个mapper。

 #!/usr/bin/env python
 # -*- coding: utf-8 -*-

 import sys

 for line in sys.stdin: #接受系统的标准输入
     line = line.strip()
     lists = line.split()
     print 'ip=%s|time=%s|path=%s' %(lists[0],lists[3].strip('[]'),lists[6])#处理成想要的结果

3.测试程序执行命令

hadoop jar /home/biedong/hadoop-2.7.0/share/hadoop/tools/lib/hadoop-streaming-2.7.0.jar -mapper /home/biedong/test/mapper1.py -input /home/zuoye/access.log -output /home/zuoye/book-output

执行报错:提示找不多执行程序, 比如“Caused by: java.io.IOException: Cannot run program “/user/hadoop/Mapper”: error=2, No such file or directory”:

解决办法:可在提交作业时,采用-file选项指定这些文件, 比如上面例子中,可以使用“-file Mapper -file Reducer” 或者 “-file Mapper.py -file Reducer.py”, 这样,Hadoop会将这两个文件自动分发到各个节点上。

hadoop jar /home/biedong/hadoop-2.7.0/share/hadoop/tools/lib/hadoop-streaming-2.7.0.jar -mapper /home/biedong/test/mapper1.py -file /home/biedong/test/mapper1.py -input /home/zuoye/access.log -output /home/zuoye/book-output

执行完成后在hdfs上的结果:文件输出正常,结果也正常1904条。

4.加个reducer吧,这个比较简单,因为mapper已经处理好了,我直接接受mapper的输入,完了直接打印出来。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys

for line in sys.stdin:
    print line

问题是:多出一个空行

原因查找:默认情况下,Streaming使用\t分离记录中得键和值,当没有\t时,整个记录被视为键,值为空白文本。 在mapper输出的时候会自动在尾行加上\t 因此在reducer接受后,会把数据直接按照\t拆分成k和v两个,只是k是mapper的数据行,v是空白,如果咱们直接输出结果的话,就会有空白行。

Python实现Hadoop MapReduce程序的更多相关文章

  1. 使用Python实现Hadoop MapReduce程序

    转自:使用Python实现Hadoop MapReduce程序 英文原文:Writing an Hadoop MapReduce Program in Python 根据上面两篇文章,下面是我在自己的 ...

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

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

  3. Intellij idea开发Hadoop MapReduce程序

    1.首先下载一个Hadoop包,仅Hadoop即可. http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.6.0/hadoop-2.6.0 ...

  4. Hadoop MapReduce程序中解决第三方jar包问题方案

    hadoop怎样提交多个第三方jar包? 方案1:把所有的第三方jar和自己的class打成一个大的jar包,这种方案显然笨拙,而且更新升级比较繁琐. 方案2: 在你的project里面建立一个lib ...

  5. hadoop——在命令行下编译并运行map-reduce程序 2

     hadoop map-reduce程序的编译需要依赖hadoop的jar包,我尝试javac编译map-reduce时指定-classpath的包路径,但无奈hadoop的jar分布太散乱,根据自己 ...

  6. hadoop-初学者写map-reduce程序中容易出现的问题 3

    1.写hadoop的map-reduce程序之前所必须知道的基础知识: 1)hadoop map-reduce的自带的数据类型: Hadoop提供了如下内容的数据类型,这些数据类型都实现了Writab ...

  7. 用PHP编写Hadoop的MapReduce程序

    用PHP编写Hadoop的MapReduce程序     Hadoop流 虽然Hadoop是用Java写的,但是Hadoop提供了Hadoop流,Hadoop流提供一个API, 允许用户使用任何语言编 ...

  8. 攻城狮在路上(陆)-- 配置hadoop本地windows运行MapReduce程序环境

    本文的目的是实现在windows环境下实现模拟运行Map/Reduce程序.最终实现效果:MapReduce程序不会被提交到实际集群,但是运算结果会写入到集群的HDFS系统中. 一.环境说明:     ...

  9. Writing an Hadoop MapReduce Program in Python

    In this tutorial I will describe how to write a simpleMapReduce program for Hadoop in thePython prog ...

随机推荐

  1. 【JavaWeb】MVC案例之新闻列表

    MVC案例之新闻列表 作者:白宁超 2016年6月6日15:26:30 摘要:本文主要针对javaweb基本开发之MVC案例的简单操作,里面涉及mysql数据库及表的创建,以及jsp页面和servle ...

  2. .net 过滤特殊字符

    /// <summary> /// 过滤标记 /// </summary> /// <param name="NoHTML">包括HTML,脚本 ...

  3. linux文件系统节点详解

    linux文件系统有两层结构,逻辑结构和物理结构.也就是inode和block. 每个文件都有一个inode, 记录文件属性:权限,时间还有最重要的block号码. block是实际存放文件内容的地方 ...

  4. MUMmer 3使用方法

    DNA和核苷酸的快速比对软件包,基于suffix tree 数据结构,快速.图形化.模块可用于其他软件.可进行大基因组比对.多对多基因组比对. The MUMmer Home Page The MUM ...

  5. 谈谈HttpUrlConnection与DefaultHttpClient一些区别

    HttpClient封装的很庞大,很复杂,你必须按照,他封装的思想去使用它,导致它很不灵活. 相比之下,HttpUrlConnection很轻巧,很方便,很灵活. HttpClient对于数据上面的封 ...

  6. PowerDesigner 将CDM、PDM导出为图片

    选中所有对象(Ctrl + A),复制(Ctrl + C),打开系统的“画图”软件,粘贴(Ctrl + V),另存为BMP或者PNG格式即可. 如果是将图片粘贴到Word文档也是可行的.

  7. HTTP协议报文、工作原理及Java中的HTTP通信技术详解

    一.web及网络基础       1.HTTP的历史            1.1.HTTP的概念:                 HTTP(Hyper Text Transfer Protocol ...

  8. FastDFS配置过程

    在我的生产环境中利用FastDFS实现动静分离的方案

  9. Gems

    zoj2332:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2332 题意:这一道题的题意,我看了很久,也没有看明白,最终 ...

  10. QVariant(相当于是Java里面的Object,起到一个数据类型“擦除”的作用,可以使用Q_DECLARE_METATYPE进行注册)

    =QVariant= [%这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是 ...