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

ffr*_*end 10 python mapreduce hadoop-streaming

我定义了一个MapReduce作业main.py,从中导入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
Run Code Online (Sandbox Code Playgroud)

在我的理解,这应该把两者main.pylib.py进入分布式缓存文件夹中的每个计算设备上,从而使模块lib可用main.但它没有发生:从日志中我看到文件真的被复制到同一目录,但main无法导入lib,抛出ImportError.

为什么会发生这种情况,我该如何解决?

UPD.将当前目录添加到路径不起作用:

import sys    
sys.path.append(os.path.realpath(__file__))
import lib
# ImportError
Run Code Online (Sandbox Code Playgroud)

但是,手动加载模块可以解决问题:

import imp
lib = imp.load_source('lib', 'lib.py')
Run Code Online (Sandbox Code Playgroud)

但这不是我想要的.那么为什么Python解释器会.py在同一目录中看到其他文件,但却无法导入它们?请注意,我已经尝试将空__init__.py文件添加到同一目录而不起作用.

ffr*_*end 12

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

简单的解决方法在这里是把两者main.pylib.py到同一个目录,使符号链接的目录放置到MR工作的工作目录,而这两个文件是物理上在同一个目录.所以我做了以下事情:

  1. main.pylib.pyapp目录.
  2. main.pylib.py直接使用,即导入字符串只是

    导入lib

  3. app-files选项的上传目录.

所以,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 
Run Code Online (Sandbox Code Playgroud)


小智 5

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