[英]How to import a custom module in a MapReduce job?
我在main.py
定义了一个MapReduce作业,它从lib.py
导入lib
模块。 我使用Hadoop Streaming将此作业提交到Hadoop集群,如下所示:
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -files lib.py,main.py
-mapper "./main.py map" -reducer "./main.py reduce"
-input input -output output
根据我的理解,这应该将main.py
和lib.py
放入每台计算机上的分布式缓存文件夹中 ,从而使模块lib
可用于main
。 但它没有发生:从日志中我看到文件真的被复制到同一个目录,但是main
无法导入lib
,抛出了ImportError
。
为什么会发生这种情况,我该如何解决?
UPD。 将当前目录添加到路径不起作用:
import sys
sys.path.append(os.path.realpath(__file__))
import lib
# ImportError
但是,手动加载模块可以解决问题:
import imp
lib = imp.load_source('lib', 'lib.py')
但这不是我想要的。 那么为什么Python解释器会在同一目录中看到其他.py
文件,但却无法导入它们? 请注意,我已经尝试将空的__init__.py
文件添加到同一目录而不起作用。
我将问题发布到Hadoop用户列表,最后找到答案。 事实证明,Hadoop并不真正将文件复制到命令运行的位置,而是为它们创建符号链接 。 反过来,Python无法使用符号链接,因此无法将lib.py
识别为Python模块。
这里简单的解决方法是将main.py
和lib.py
放在同一目录中,以便将目录的符号链接放入MR作业工作目录,而两个文件实际上位于同一目录中。 所以我做了以下事情:
main.py
和lib.py
放入app
目录。 在main.py
我直接使用了lib.py
,也就是说,import string就是
导入lib
使用-files
选项上传的app
目录。
所以,final命令看起来像这样:
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -files app
-mapper "app/main.py map" -reducer "app/main.py reduce"
-input input -output output
当Hadoop-Streaming启动python脚本时,python脚本的路径就是脚本文件的真实位置。 但是,hadoop以'./'开头,而你的lib.py(它是一个符号链接)也是'./'。 因此,在导入lib.py之前尝试添加'sys.path.append(“./”)',如下所示: import sys sys.path.append('./') import lib
该-files
和-archive
开关只是快捷方式Hadoop的分布式缓存 (DC),更通用的机制,也允许上传,并在拉链,焦油和TGZ /的tar.gz格式的自动解压缩档案。 如果您的库是由结构化Python包实现的,而不是单个模块,则后一个功能就是您想要的。
我们在发布1.0.0-rc1后直接在Pydoop中支持这个,你可以在其中简单地构建一个mypkg.tgz
存档并运行你的程序:
pydoop submit --upload-archive-to-cache mypkg.tgz [...]
相关文档位于http://crs4.github.io/pydoop/self_contained.html ,这是一个完整的工作示例(需要轮子 ): https : //github.com/crs4/pydoop/tree/master/examples/自我包容 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.