我在 main.py
中定义了MapReduce作业,该作业从 lib
导入lib.py
模块。我使用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
可用于{ {1}}。但它不会发生:从日志中我看到文件真的被复制到同一目录,但main
无法导入main
,抛出 { {1}}
为什么会发生这种情况,我该如何解决?
UPD。将当前目录添加到路径不起作用:
lib
但是,手动加载模块可以解决问题:
ImportError
但这不是我想要的。那么为什么Python解释器会在同一目录中看到其他import sys
sys.path.append(os.path.realpath(__file__))
import lib
# ImportError
文件,但却无法导入它们?请注意,我已经尝试将空import imp
lib = imp.load_source('lib', 'lib.py')
文件添加到同一目录而不起作用。
答案 0 :(得分:12)
我将问题发布到Hadoop用户列表,最后找到答案。事实证明,Hadoop并不真正将文件复制到命令运行的位置,而是为它们创建符号链接。反过来,Python无法使用符号链接,因此无法将lib.py
识别为Python模块。
简单解决方法这里是将main.py
和lib.py
放在同一目录中,以便符号链接到目录放入MR作业工作目录,而两个文件在物理上位于同一目录中。所以我做了以下事情:
main.py
和lib.py
放入app
目录。 在main.py
我直接使用lib.py
,即导入字符串只是
import lib
使用app
选项上传-files
目录。
所以,最终命令看起来像这样:
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
答案 1 :(得分:3)
当Hadoop-Streaming启动python脚本时,你的python脚本的路径就是脚本文件的真实位置。然而,hadoop在' ./'开始它们,而你的lib.py(它的符号链接)也在' ./'。因此,尝试添加' sys.path.append(" ./")'在导入lib.py之前:
import sys
sys.path.append('./')
import lib
答案 2 :(得分:1)
-files
和-archive
开关只是Hadoop distributed cache(DC)的快捷方式,这是一种更通用的机制,也允许上传并自动解压缩zip,tar和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,这是一个完整的工作示例(需要wheel):https://github.com/crs4/pydoop/tree/master/examples/self_contained。