我在 main.py
中定义了一个 MapReduce 作业,它从 lib.py 导入
。我使用 Hadoop Streaming 将此作业提交到 Hadoop 集群,如下所示:lib
模块
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 并没有真正将文件复制到命令运行的位置,而是为它们创建符号链接(symbolic link)。反过来,Python 不能使用符号链接(symbolic link),因此不能将 lib.py
识别为 Python 模块。
这里的简单解决方法是将main.py
和lib.py
放在同一个目录中,这样符号链接(symbolic link)到该目录 放置在 MR 作业工作目录中,而两个文件在物理上位于同一目录中。所以我做了以下事情:
- 将
main.py
和lib.py
放入app
目录。 在
main.py
中我直接使用了lib.py
,即import string就是导入库
使用
-files
选项上传app
目录。
所以,最后的命令是这样的:
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