如何在MapReduce作业中导入自定义模块?

时间:2013-08-09 15:22:22

标签: python mapreduce hadoop-streaming

我在 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.pylib.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') 文件添加到同一目录而不起作用。

3 个答案:

答案 0 :(得分:12)

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

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

  1. main.pylib.py放入app目录。
  2. main.py我直接使用lib.py,即导入字符串只是

    import lib

  3. 使用app选项上传-files目录。

  4. 所以,最终命令看起来像这样:

    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