12

我在 中定义了一个 MapReduce 作业main.py,它liblib.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中,从而使模块可用于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文件添加到同一目录但没有效果。

4

3 回答 3

16

我将问题发布到 Hadoop 用户列表,终于找到了答案。事实证明,Hadoop 并没有真正将文件复制到命令运行的位置,而是为它们创建符号链接。反过来,Python 不能使用符号链接,因此不能识别lib.py为 Python 模块。

这里简单的解决方法是将两者都放在main.pylib.py一个目录中,以便目录的符号链接放在 MR 作业工作目录中,而两个文件在物理上位于同一个目录中。所以我做了以下事情:

  1. 放入目录。main.py_lib.pyapp
  2. main.pylib.py直接用的,也就是import string就是

    导入库

  3. 带有选项的上传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 
于 2013-08-13T11:16:54.163 回答
5

当 Hadoop-Streaming 启动 python 脚本时,python 脚本的路径就是脚本文件的真正位置。但是,hadoop 从 './' 开始它们,而您的 lib.py(它是一个符号链接)也在 './' 处。因此,尝试在导入 lib.py 之前添加 'sys.path.append("./")',如下所示: import sys sys.path.append('./') import lib

于 2015-01-27T09:25:20.403 回答
1

-files-archive开关只是 Hadoop分布式缓存(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/自包含

于 2015-01-27T09:58:47.790 回答