一個小需求,不想寫java的mapreduce的程式,想用streaming + python 處理一下就行了,遇到一些問題,做個筆記。
以後遇到這樣的情境,可以放心使用了。
我是在windows 下的 pyCharm 編寫的mapper 和 reducer ,直接上傳到linux伺服器,發現根本運行不了,老是報:
./maper.py file or directory not find
而且找不到原因,後來發現是windows和linux檔案格式差異造成的。
也算是個教訓吧。
python shell 指令碼如果在windows上編寫,到linux上運行,需要轉換一下格式: dos2unix + 檔案名稱
看一下python指令碼:
mapper.py
#!/usr/bin/python#coding:utf8import jsonimport sysimport rewrapper = ["fqa","fqq","gtt","zxb","zxa"]for line in sys.stdin: try: line = line.decode("utf8") str = re.split("\\s+",line)[2].strip() s = json.loads(str) if len(s["data"]["tts"]) == 0: continue minPr = sys.maxint for prline in s["data"]["tts"]: pr = prline["pr"] minPr = min(minPr,pr) for l in s["data"]["tts"]: if l["cl"] in wrapper: if l["pr"]==minPr: print "%s-%s,%s\t%s" % (l["dc"],l["ac"],l["cl"],"1") else: print "%s-%s,%s\t%s" % (l["dc"],l["ac"],l["cl"],"0") except Exception,ex: pass</span>
reducer.py :
#!/usr/bin/env pythonimport systcount = 0.0lcount = 0.0lastkey = ""for line in sys.stdin: key,val = line.split('\t') if lastkey != key and lastkey != "": lastkey = key print "%s\t%d\t%d\t%f" % (lastkey,tcount,lcount,lcount/tcount) tcount = 0.0 lcount = 0.0 elif lastkey == "": lastkey = key tcount += 1 if val.strip() == "1": lcount += 1
代碼中需要注意的有:
#!/usr/bin/env python#coding:utf8line = line.decode("utf8")try:except Exception,ex: pass
這些點都需要注意,否則,一個小問題就會導致任務失敗
其中,如果輸入資料中有髒資料,python指令碼拋異常,但是如果代理裡沒有處理異常,就會報錯,類型下面的:
minRecWrittenToEnableSkip_=9223372036854775807 HOST=nullUSER=datadevHADOOP_USER=nulllast tool output: |LLA-AMS,zxl0|java.io.IOException: Broken pipeat java.io.FileOutputStream.writeBytes(Native Method)at java.io.FileOutputStream.write(FileOutputStream.java:345)at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122)at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122)at java.io.DataOutputStream.write(DataOutputStream.java:107)at org.apache.hadoop.streaming.io.TextInputWriter.writeUTF8(TextInputWriter.java:72)at org.apache.hadoop.streaming.io.TextInputWriter.writeValue(TextInputWriter.java:51)at org.apache.hadoop.streaming.PipeMapper.map(PipeMapper.java:106)at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:54)at org.apache.hadoop.streaming.PipeMapRunner.run(PipeMapRunner.java:34)at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:429)at org.apache.hadoop.mapred.MapTask.run(MapTask.java:341)at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:162)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:1491)at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:157)
把異常拋給了hadoop架構處理,它當然是按照錯誤來處理,報錯,退出。
看一下提交作業指令碼,這個也很重要:
#!/bin/bashexport HADOOP_HOME=/home/q/hadoop-2.2.0sudo -u flightdev hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.2.0.jar \ -D mapred.job.queue.name=queue1 \ -D stream.map.input.ignoreKey=true \ -inputformat com.hadoop.mapred.DeprecatedLzoTextInputFormat \ -input /input/date=2014-11-17.lzo/* \ -output /output/20141117 \ -mapper maper.py \ -file maper.py \ -reducer reducer.py \ -file reducer.py
下面兩點需要注意
-D stream.map.input.ignoreKey=true \ -inputformat com.hadoop.mapred.DeprecatedLzoTextInputFormat \
表示忽略輸入的lzo檔案中的行號,避免行號對輸入資料的影響