文章目录
  1. 1. 问题
  2. 2. 解决方案
  3. 3. 参考

问题

今天发现用Python编写Hadoop Streaming脚本时,如果自己导入自定义的模块会报错-_-
列如word count中的reducer程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env python
#-*- coding=utf8 -*-

import sys
import utils_helper

lastk = None #这里标志最后一个k 用于控制同一个key 到一个组中
count = 0


for line in sys.stdin:
w,c = line.split('\t')
c = int(c) #不转成int会比较麻烦 这是是计数
if lastk == None: #这里是判断是否过来的是第一个key
lastk=w
count = utils_helper.add(count,c)
elif lastk == w:
count += c
else:
print "%s\t%s"%(lastk,count)
lastk=w
count = c #这里重置计数

if lastk is not None:
print "%s\t%s"%(lastk,count)

故意使用一个自定义模块来测试utils_helper.py

1
2
3
4
#! /usr/bin/env python

def add(x,y):
return x+y

如果本地跑起来是(就是本地DEBUG)就可以正常跑的,但是放到Hadoop集群上跑的时候,使用的启动命令为:

hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.7.0.jar \
-input /yyl/data/line.txt \
-output /yyl/test/ouput/streaming2 \
-mapper "python word_count_mapper.py" \
-reducer "python word_count_reducer.py" \
-file $HADOOP_HOME/runjar/pyscript/word_count_mapper.py \
-file $HADOOP_HOME/runjar/pyscript/word_count_reducer.py \
-file $HADOOP_HOME/runjar/pyscript/utils_helper.py \

可以发现跑到reducer阶段时会报错:

16/03/24 12:11:40 INFO mapreduce.Job: Running job: job_1458827745768_0018
16/03/24 12:11:53 INFO mapreduce.Job: Job job_1458827745768_0018 running in uber mode : false
16/03/24 12:11:53 INFO mapreduce.Job:  map 0% reduce 0%
16/03/24 12:12:12 INFO mapreduce.Job:  map 100% reduce 0%
16/03/24 12:12:22 INFO mapreduce.Job: Task Id : attempt_1458827745768_0018_r_000000_0, Status : FAILED
Error: java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 2
    at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:322)
    at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:535)
    at org.apache.hadoop.streaming.PipeReducer.close(PipeReducer.java:134)
    at org.apache.hadoop.io.IOUtils.cleanup(IOUtils.java:244)
    at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:459)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:392)
    at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:163)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:415)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657)
    at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158)

这就疼了,代码应该没问题呀,尝试了好几遍之后还是这个错误。。。-_-!!

解决方案

后来在stackoverflow发现有人问了同样的问题,并且我使用其中一个方案解决了:

When Hadoop-Streaming starts the python scripts, your python script's path is where the script file really is. However, hadoop starts them at './', and your lib.py(it's a symlink) is at './', too. So, try to add 'sys.path.append("./")' before you import lib.py like this: 
import sys
sys.path.append('./')
import lib

lib.py表示自定义包

应该就是-file上传到计算机器之后文件路径的问题产生的,不过感觉他的理由有点疑惑,按他说的如果我上传之后会通过软连接组织到同一目录下再使用,所以如果直接导入包可能会出问题,那我如果上传之前就是在同一目录下应该就不会出问题吧??这里并不是很理解,但是至少是导入包的问题是解决了^_^

参考

  1. http://stackoverflow.com/questions/18150208/how-to-import-a-custom-module-in-a-mapreduce-job

本作品采用[知识共享署名-非商业性使用-相同方式共享 2.5]中国大陆许可协议进行许可,我的博客欢迎复制共享,但在同时,希望保留我的署名权kubiCode,并且,不得用于商业用途。如您有任何疑问或者授权方面的协商,请给我留言

文章目录
  1. 1. 问题
  2. 2. 解决方案
  3. 3. 参考