1 使用cacheFile分發(fā)文件
如果文件(如字典文件)存放在HDFS中洲守,希望計算時在每個計算節(jié)點上將文件當作本地文件處理,沾凄,可以使用-cacheFile hdfs://host:port/path/to/file#linkname選項在計算節(jié)點緩存文件梗醇,Streaming程序通過./linkname訪問文件。
例如:
hadoop = `which hadoop`
$hadoop streaming \
-input /user/test/input -output /user/test/output \
-mapper mymapper.sh -reducer myreducer.sh \
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh \
-cacheFile hdfs://namenode:port/user/test/dict.data#dictlink \
-jobconf mapred.job.name=”cache-file-demo”
mymapper.sh和myreducer.sh可以通過./dictlink直接訪問字典文件hdfs://user/test/dict.data撒蟀,而且是從本地讀取文件叙谨。
2?用cacheArchive分發(fā)壓縮包
有時要分發(fā)的文件有一定的目錄結(jié)構(gòu),可以先將整個目錄打包保屯,然后整體進行上傳手负。使用-cacheArchive hdfs://host:port/path/to/archivefile#linkname分發(fā)壓縮包。
例如在本地有一個目錄為app姑尺,里面有mapper.pl, reducer.pl, dict/dict.txt這些子目錄和文件竟终,mapper.pl和reducer.pl要讀取./dict/dict.txt文件,希望在任務(wù)執(zhí)行時不需要修改程序和目錄結(jié)構(gòu)切蟋,?可以按照下面的方式分發(fā)app目錄:
$ tar app.tar.gz –C app .? #本地打包
$ $HADOOP_HOME/bin/hadoop fs –put app.tar.gz /user/test/app.tar.gz?? #包上傳到HDFS
$ $HADOOP_HOME/bin/hadoop streaming \
-input /user/test/input -output /user/test/output \
-mapper “perl app/mapper.pl” -reducer “perl app/reducer.pl” \
-cacheArchive hdfs://namenode:port/user/test/ app.tar.gz #app \
-jobconf mapred.job.name=”cache-archive-demo”
首先將本地app目錄中的所有文件和目錄打包壓縮统捶,然后上傳到HDFS的/user/test/app.tar.gz,啟動streaming任務(wù)時使用-cacheArchive選項將app.tar.gz分發(fā)到計算節(jié)點并解壓到app目錄柄粹,然后在當前工作目錄創(chuàng)建到app目錄的鏈接喘鸟,-mapper選項指定app/mapper.pl為mapper程序,-reducer選項指定app/reducer.pl為reducer程序驻右,它們都可以讀取./dict/dict.txt文件什黑。本地打包時要進入目錄app而不是在app的上層目錄打包,否則要通過app/app/mapper.pl才能訪問到mapper.pl文件堪夭。
hadoop支持zip, jar, tar.gz格式的壓縮包愕把,由于Java解壓zip壓縮包時會丟失文件權(quán)限信息而且遇到中文文件名會出錯拣凹,所見建議采用tar.gz壓縮包。
三種文件分發(fā)方式的區(qū)別:-file將客戶端本地文件打成jar包上傳到HDFS然后分發(fā)到計算節(jié)點恨豁,-cacheFile將HDFS文件分發(fā)到計算節(jié)點嚣镜,-cacheArchive將HDFS壓縮文件分發(fā)到計算節(jié)點并解壓。
3輸出數(shù)據(jù)分割
默認情況下Streaming框架將map輸出的每一行第一個”\t”之前的部分作為key圣絮,之后的部分作為value祈惶,key\tvalue又作為reduce的輸入雕旨“缃常可以用-D stream.map.output.field.separator改變map輸出中key和value的分隔符,用-D stream.num.map.output.key.fields設(shè)置分隔符的位置凡涩,該位置之前的部分作為key棒搜,之后的部分作為value。如下所示活箕,其中-D stream.map. output.field.separator=:指定使用冒號”:”將map輸出的一行分隔為key/value力麸,-D stream.num.map.output.key.fields=2指定在第二個冒號處進行分隔,也就是第二個冒號之前的作為key育韩,之后的作為value克蚂。如果沒有冒號或冒號少于兩個,則key為整行筋讨,value為空埃叭。
$HADOOP_HOME/bin/hadoop streaming \
???? ? -D stream.map.output.field.separator=: \
?????? -D stream.num.map.output.key.fields=2 \
-input /user/test/input -output /user/test/output \
-mapper mymapper.sh -reducer myreducer.sh \
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh?\
-jobconf mapred.job.name=”output-sep-demo”
與map類似,對于reduce的輸出悉罕,同樣也可以用-D stream.reduce.output.field.separator和-D stream.num.reduce.output.key.fields定制key/value分隔方式赤屋。
4?二次排序
KeyFieldBasedPartitioner是Hadoop庫中的一個實用Partitioner,配置相應(yīng)的參數(shù)就可以使用壁袄,通過KeyFieldBasedPartitioner可以方便地實現(xiàn)二次排序类早。
$HADOOP_HOME/bin/hadoop streaming \
-D stream.map.output.field.separator=.?\
?????? -D stream.num.map.output.key.fields=4 \
?????? -D map.output.key.field.separator=. \
?????? -D num.key.fields.for.partition=2 \
-input /user/test/input -output /user/test/output \
-mapper “mymapper.sh” -reducer “ myreducer.sh” \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner?\
-file /home/work/mymapper.sh \
-file /home/work/myreducer.sh?\
-jobconf mapred.job.name=”key-partition-demo”
其中-Dstream.map.output.field.separator=.和-D stream.num.map.output.key.fields=4與上面的定制輸出數(shù)據(jù)分隔方式意義相同,指定map的輸出行第4個英文句號”.”之前為key嗜逻,后面為value涩僻。-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner指定使用KeyFieldBasedPartitioner,-D map.output.key.field.separator=.指定key的內(nèi)部用英文句號”.”分隔栈顷,-D num.key.fields.for.partition=2指定將key分隔出來的前兩個部分而不是整個key用于Partitioner做partition令哟。