用python + hadoop streaming 分布式编程(一) -- 原理介绍,样例程序与本地调试


Posted in Python onJuly 14, 2014

MapReduce与HDFS简介
什么是Hadoop?

Google为自己的业务需要提出了编程模型MapReduce和分布式文件系统Google File System,并发布了相关论文(可在Google Research的网站上获得: GFS 、 MapReduce)。 Doug Cutting和Mike Cafarella在开发搜索引擎Nutch时对这两篇论文做了自己的实现,即同名的MapReduce和HDFS,合起来就是Hadoop。

MapReduce的Data flow如下图,原始数据经过mapper处理,再进行partition和sort,到达reducer,输出最后结果。

用python + hadoop streaming 分布式编程(一) -- 原理介绍,样例程序与本地调试

图片来自Hadoop: The Definitive Guide

Hadoop Streaming原理
Hadoop本身是用Java开发的,程序也需要用Java编写,但是通过Hadoop Streaming,我们可以使用任意语言来编写程序,让Hadoop运行。

Hadoop Streaming的相关源代码可以在Hadoop的Github repo 查看。简单来说,就是通过将用其他语言编写的mapper和reducer通过参数传给一个事先写好的Java程序(Hadoop自带的*-streaming.jar),这个Java程序会负责创建MR作业,另开一个进程来运行mapper,将得到的输入通过stdin传给它,再将mapper处理后输出到stdout的数据交给Hadoop,partition和sort之后,再另开进程运行reducer,同样地通过stdin/stdout得到最终结果。因此,我们只需要在其他语言编写的程序里,通过stdin接收数据,再将处理过的数据输出到stdout,Hadoop streaming就能通过这个Java的wrapper帮我们解决中间繁琐的步骤,运行分布式程序。

用python + hadoop streaming 分布式编程(一) -- 原理介绍,样例程序与本地调试

图片来自Hadoop: The Definitive Guide

原理上只要是能够处理stdio的语言都能用来写mapper和reducer,也可以指定mapper或reducer为Linux下的程序(如awk、grep、cat)或者按照一定格式写好的java class。因此,mapper和reducer也不必是同一类的程序。

Hadoop Streaming的优缺点

优点

可以使用自己喜欢的语言来编写MapReduce程序(换句话说,不必写Java XD)
不需要像写Java的MR程序那样import一大堆库,在代码里做一大堆配置,很多东西都抽象到了stdio上,代码量显著减少
因为没有库的依赖,调试方便,并且可以脱离Hadoop先在本地用管道模拟调试

缺点

只能通过命令行参数来控制MapReduce框架,不像Java的程序那样可以在代码里使用API,控制力比较弱,有些东西鞭长莫及
因为中间隔着一层处理,效率会比较慢
所以Hadoop Streaming比较适合做一些简单的任务,比如用python写只有一两百行的脚本。如果项目比较复杂,或者需要进行比较细致的优化,使用Streaming就容易出现一些束手束脚的地方。

用python编写简单的Hadoop Streaming程序

这里提供两个例子:

Michael Noll的word count程序
Hadoop: The Definitive Guide里的例程
使用python编写Hadoop Streaming程序有几点需要注意:

在能使用iterator的情况下,尽量使用iterator,避免将stdin的输入大量储存在内存里,否则会严重降低性能

streaming不会帮你分割key和value传进来,传进来的只是一个个字符串而已,需要你自己在代码里手动调用split()

从stdin得到的每一行数据末尾似乎会有\n,保险起见一般都需要使用rstrip()来去掉

在想获得K-V list而不是一个个处理key-value pair时,可以使用groupby配合itemgetter将key相同的k-v pair组成一个个group,得到类似Java编写的reduce可以直接获取一个Text类型的key和一个iterable作为value的效果。注意itemgetter的效率比lambda表达式要高,所以如果需求不是很复杂的话,尽量用itemgetter比较好。

我在编写Hadoop Streaming程序时的基本模版是

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Some description here...
"""

import sys
from operator import itemgetter
from itertools import groupby

def read_input(file):
 """Read input and split."""
 for line in file:
  yield line.rstrip().split('\t')

def main():
 data = read_input(sys.stdin)
 for key, kviter in groupby(data, itemgetter(0)):
  # some code here..

if __name__ == "__main__":
 main()

如果对输入输出格式有不同于默认的控制,主要会在read_input()里调整。

本地调试

本地调试用于Hadoop Streaming的python程序的基本模式是:

$ cat <input path> | python <path to mapper script> | sort -t $'\t' -k1,1 | python <path to reducer script> > <output path>

或者如果不想用多余的cat,也可以用<定向

$ python <path to mapper script> < <input path> | sort -t $'\t' -k1,1 | python <path to reducer script> > <output path>

这里有几点需要注意:

Hadoop默认按照tab来分割key和value,以第一个分割出的部分为key,按key进行排序,因此这里使用

sort -t $'\t' -k1,1
来模拟。如果你有其他需求,在交给Hadoop Streaming执行时可以通过命令行参数调,本地调试也可以进行相应的调整,主要是调整sort的参数。因此为了能够熟练进行本地调试,建议先掌握sort命令的用法。

如果你在python脚本里加上了shebang,并且为它们添加了执行权限,也可以用类似于

./mapper.py

来代替

python mapper.py
Python 相关文章推荐
python实现2014火车票查询代码分享
Jan 10 Python
用Python制作检测Linux运行信息的工具的教程
Apr 01 Python
python类和继承用法实例
Jul 07 Python
python3.4.3下逐行读入txt文本并去重的方法
Apr 29 Python
Python脚本按照当前日期创建多级目录
Mar 01 Python
Python中使用双下划线防止类属性被覆盖问题
Jun 27 Python
Python编程快速上手——选择性拷贝操作案例分析
Feb 28 Python
python中读入二维csv格式的表格方法详解(以元组/列表形式表示)
Apr 24 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
Jun 18 Python
推荐技术人员一款Python开源库(造数据神器)
Jul 08 Python
python中lower函数实现方法及用法讲解
Dec 23 Python
Python3爬虫RedisDump的安装步骤
Feb 20 Python
用python + openpyxl处理excel2007文档思路以及心得
Jul 14 #Python
Python库urllib与urllib2主要区别分析
Jul 13 #Python
Python文件夹与文件的操作实现代码
Jul 13 #Python
分享15个最受欢迎的Python开源框架
Jul 13 #Python
使用 Python 获取 Linux 系统信息的代码
Jul 13 #Python
Python文件操作类操作实例详解
Jul 11 #Python
Python编写检测数据库SA用户的方法
Jul 11 #Python
You might like
第十三节 对象串行化 [13]
2006/10/09 PHP
mysql5的sql文件导入到mysql4的方法
2008/10/19 PHP
php数组函数序列之ksort()对数组的元素键名进行升序排序,保持索引关系
2011/11/02 PHP
php实现扫描二维码根据浏览器类型访问不同下载地址
2014/10/15 PHP
ThinkPHP自定义函数解决模板标签加减运算的方法
2015/07/03 PHP
TP5框架简单登录功能实现方法示例
2019/10/31 PHP
jquery $.ajax入门应用一
2008/11/19 Javascript
javascript 通用简单的table选项卡实现
2010/05/07 Javascript
js querySelector和getElementById通过id获取元素的区别
2012/04/20 Javascript
IE网页js语法错误2行字符1、FF中正常的解决方法
2013/09/09 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
浅谈JS正则表达式的RegExp对象和括号的使用
2016/07/28 Javascript
JS中使用DOM来控制HTML元素
2016/07/31 Javascript
对js eval()函数的一些见解
2016/08/15 Javascript
JS对大量数据进行多重过滤的方法
2016/11/04 Javascript
使用snowfall.jquery.js实现爱心满屏飞的效果
2017/01/05 Javascript
Vue代码分割懒加载的实现方法
2017/11/23 Javascript
微信小程序tabBar用法实例详解
2017/12/04 Javascript
利用vue开发一个所谓的数独方法实例
2017/12/21 Javascript
Vue的Eslint配置文件eslintrc.js说明与规则介绍
2020/02/03 Javascript
[51:17]Mski vs VGJ.S Supermajor小组赛C组 BO3 第三场 6.3
2018/06/04 DOTA
Python中decorator使用实例
2015/04/14 Python
Python实现批量将word转html并将html内容发布至网站的方法
2015/07/14 Python
python删除过期log文件操作实例解析
2018/01/31 Python
python如何派生内置不可变类型并修改实例化行为
2018/03/21 Python
python使用pandas处理大数据节省内存技巧(推荐)
2019/05/05 Python
Python 二叉树的层序建立与三种遍历实现详解
2019/07/29 Python
pytorch实现focal loss的两种方式小结
2020/01/02 Python
Python configparser模块常用方法解析
2020/05/22 Python
PyInstaller运行原理及常用操作详解
2020/06/13 Python
安全生产知识竞赛活动总结
2014/07/07 职场文书
冰峪沟导游词
2015/02/09 职场文书
教师节倡议书2015
2015/04/27 职场文书
酒店温馨提示语
2015/07/14 职场文书
教你快速开启Apache SkyWalking的自监控
2021/04/25 Servers
mysql left join快速转inner join的过程
2021/06/30 MySQL