| <?xml version="1.0" encoding="utf-8"?> |
| <!-- |
| Copyright 2002-2004 The Apache Software Foundation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" |
| "http://forrest.apache.org/dtd/document-v20.dtd"> |
| |
| |
| <document> |
| <header> |
| <title>Hadoop Streaming</title> |
| <meta name="http-equiv">Content-Type</meta> |
| <meta name="content">text/html;</meta> |
| <meta name="charset">utf-8</meta> |
| </header> |
| <body> |
| <section> |
| <title>Hadoop Streaming</title> |
| <p> |
| Hadoop streaming是Hadoop的一个工具, |
| 它帮助用户创建和运行一类特殊的map/reduce作业, |
| 这些特殊的map/reduce作业是由一些可执行文件或脚本文件充当mapper或者reducer。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper /bin/cat \ |
| -reducer /bin/wc |
| </source> |
| </section> |
| |
| <section> |
| <title>Streaming工作原理</title> |
| <p> |
| 在上面的例子里,mapper和reducer都是可执行文件,它们从标准输入读入数据(一行一行读), |
| 并把计算结果发给标准输出。Streaming工具会创建一个Map/Reduce作业, |
| 并把它发送给合适的集群,同时监视这个作业的整个执行过程。 |
| </p><p> |
| 如果一个可执行文件被用于mapper,则在mapper初始化时, |
| 每一个mapper任务会把这个可执行文件作为一个单独的进程启动。 |
| mapper任务运行时,它把输入切分成行并把每一行提供给可执行文件进程的标准输入。 |
| 同时,mapper收集可执行文件进程标准输出的内容,并把收到的每一行内容转化成key/value对,作为mapper的输出。 |
| 默认情况下,一行中第一个tab之前的部分作为<strong>key</strong>,之后的(不包括tab)作为<strong>value</strong>。 |
| 如果没有tab,整行作为key值,value值为null。不过,这可以定制,在下文中将会讨论如何自定义key和value的切分方式。 |
| </p> |
| <p>如果一个可执行文件被用于reducer,每个reducer任务会把这个可执行文件作为一个单独的进程启动。 |
| Reducer任务运行时,它把输入切分成行并把每一行提供给可执行文件进程的标准输入。 |
| 同时,reducer收集可执行文件进程标准输出的内容,并把每一行内容转化成key/value对,作为reducer的输出。 |
| 默认情况下,一行中第一个tab之前的部分作为key,之后的(不包括tab)作为value。在下文中将会讨论如何自定义key和value的切分方式。 |
| </p><p> |
| 这是Map/Reduce框架和streaming mapper/reducer之间的基本通信协议。 |
| </p><p> |
| 用户也可以使用java类作为mapper或者reducer。上面的例子与这里的代码等价: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper org.apache.hadoop.mapred.lib.IdentityMapper \ |
| -reducer /bin/wc |
| </source> |
| <p>用户可以设定<code>stream.non.zero.exit.is.failure</code> |
| <code>true</code> 或<code>false</code> 来表明streaming task的返回值非零时是 |
| <code>Failure</code> |
| 还是<code>Success</code>。默认情况,streaming task返回非零时表示失败。 |
| </p> |
| </section> |
| |
| <section> |
| <title>将文件打包到提交的作业中</title> |
| <p> |
| 任何可执行文件都可以被指定为mapper/reducer。这些可执行文件不需要事先存放在集群上; |
| 如果在集群上还没有,则需要用-file选项让framework把可执行文件作为作业的一部分,一起打包提交。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper myPythonScript.py \ |
| -reducer /bin/wc \ |
| -file myPythonScript.py |
| </source> |
| <p> |
| 上面的例子描述了一个用户把可执行python文件作为mapper。 |
| 其中的选项“-file myPythonScirpt.py”使可执行python文件作为作业提交的一部分被上传到集群的机器上。 |
| </p> |
| <p> |
| 除了可执行文件外,其他mapper或reducer需要用到的辅助文件(比如字典,配置文件等)也可以用这种方式打包上传。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper myPythonScript.py \ |
| -reducer /bin/wc \ |
| -file myPythonScript.py \ |
| -file myDictionary.txt |
| </source> |
| </section> |
| |
| <section> |
| <title>Streaming选项与用法</title> |
| |
| <section> |
| <title>只使用Mapper的作业</title> |
| <p> |
| 有时只需要map函数处理输入数据。这时只需把mapred.reduce.tasks设置为零,Map/reduce框架就不会创建reducer任务,mapper任务的输出就是整个作业的最终输出。 |
| </p><p> |
| 为了做到向下兼容,Hadoop Streaming也支持“-reduce None”选项,它与“-jobconf mapred.reduce.tasks=0”等价。 |
| </p> |
| </section> |
| |
| <section> |
| <title>为作业指定其他插件</title> |
| <p> |
| 和其他普通的Map/Reduce作业一样,用户可以为streaming作业指定其他插件: |
| </p> |
| <source> |
| -inputformat JavaClassName |
| -outputformat JavaClassName |
| -partitioner JavaClassName |
| -combiner JavaClassName |
| </source> |
| <p>用于处理输入格式的类要能返回Text类型的key/value对。如果不指定输入格式,则默认会使用TextInputFormat。 |
| 因为TextInputFormat得到的key值是LongWritable类型的(其实key值并不是输入文件中的内容,而是value偏移量), |
| 所以key会被丢弃,只把value用管道方式发给mapper。 |
| </p><p> |
| 用户提供的定义输出格式的类需要能够处理Text类型的key/value对。如果不指定输出格式,则默认会使用TextOutputFormat类。 |
| </p> |
| </section> |
| |
| <section> |
| <title>Hadoop Streaming中的大文件和档案</title> |
| |
| <p>任务使用-cacheFile和-cacheArchive选项在集群中分发文件和档案,选项的参数是用户已上传至HDFS的文件或档案的URI。这些文件和档案在不同的作业间缓存。用户可以通过fs.default.name.config配置参数的值得到文件所在的host和fs_port。 |
| </p> |
| <p> |
| 这个是使用-cacheFile选项的例子: |
| </p> |
| <source> |
| -cacheFile hdfs://host:fs_port/user/testfile.txt#testlink |
| </source> |
| <p>在上面的例子里,url中#后面的部分是建立在任务当前工作目录下的符号链接的名字。这里的任务的当前工作目录下有一个“testlink”符号链接,它指向testfile.txt文件在本地的拷贝。如果有多个文件,选项可以写成: |
| </p> |
| <source> |
| -cacheFile hdfs://host:fs_port/user/testfile1.txt#testlink1 -cacheFile hdfs://host:fs_port/user/testfile2.txt#testlink2 |
| </source> |
| <p> |
| -cacheArchive选项用于把jar文件拷贝到任务当前工作目录并自动把jar文件解压缩。例如: |
| </p> |
| <source> |
| -cacheArchive hdfs://host:fs_port/user/testfile.jar#testlink3 |
| </source> |
| <p> |
| 在上面的例子中,testlink3是当前工作目录下的符号链接,它指向testfile.jar解压后的目录。 |
| </p> |
| <p> |
| 下面是使用-cacheArchive选项的另一个例子。其中,input.txt文件有两行内容,分别是两个文件的名字:testlink/cache.txt和testlink/cache2.txt。“testlink”是指向档案目录(jar文件解压后的目录)的符号链接,这个目录下有“cache.txt”和“cache2.txt”两个文件。 |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input "/user/me/samples/cachefile/input.txt" \ |
| -mapper "xargs cat" \ |
| -reducer "cat" \ |
| -output "/user/me/samples/cachefile/out" \ |
| -cacheArchive 'hdfs://hadoop-nn1.example.com/user/me/samples/cachefile/cachedir.jar#testlink' \ |
| -jobconf mapred.map.tasks=1 \ |
| -jobconf mapred.reduce.tasks=1 \ |
| -jobconf mapred.job.name="Experiment" |
| |
| $ ls test_jar/ |
| cache.txt cache2.txt |
| |
| $ jar cvf cachedir.jar -C test_jar/ . |
| added manifest |
| adding: cache.txt(in = 30) (out= 29)(deflated 3%) |
| adding: cache2.txt(in = 37) (out= 35)(deflated 5%) |
| |
| $ hadoop dfs -put cachedir.jar samples/cachefile |
| |
| $ hadoop dfs -cat /user/me/samples/cachefile/input.txt |
| testlink/cache.txt |
| testlink/cache2.txt |
| |
| $ cat test_jar/cache.txt |
| This is just the cache string |
| |
| $ cat test_jar/cache2.txt |
| This is just the second cache string |
| |
| $ hadoop dfs -ls /user/me/samples/cachefile/out |
| Found 1 items |
| /user/me/samples/cachefile/out/part-00000 <r 3> 69 |
| |
| $ hadoop dfs -cat /user/me/samples/cachefile/out/part-00000 |
| This is just the cache string |
| This is just the second cache string |
| |
| </source> |
| </section> |
| |
| <section> |
| <title>为作业指定附加配置参数</title> |
| <p> |
| 用户可以使用“-jobconf <n>=<v>”增加一些配置变量。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper org.apache.hadoop.mapred.lib.IdentityMapper\ |
| -reducer /bin/wc \ |
| -jobconf mapred.reduce.tasks=2 |
| </source> |
| <p> |
| 上面的例子中,-jobconf mapred.reduce.tasks=2表明用两个reducer完成作业。 |
| </p> |
| <p> |
| 关于jobconf参数的更多细节可以参考:<a href="ext:hadoop-default">hadoop-default.html</a></p> |
| </section> |
| |
| <section> |
| <title>其他选项</title> |
| <p> |
| Streaming 作业的其他选项如下表: |
| </p> |
| <table> |
| <tr><th>选项</th><th>可选/必须</th><th>描述</th></tr> |
| <tr><td> -cluster name </td><td> 可选 </td><td> 在本地Hadoop集群与一个或多个远程集群间切换</td></tr> |
| |
| <tr><td> -dfs host:port or local </td><td> 可选 </td><td> 覆盖作业的HDFS配置</td></tr> |
| <tr><td> -jt host:port or local </td><td> 可选 </td><td> 覆盖作业的JobTracker配置</td></tr> |
| <tr><td> -additionalconfspec specfile </td><td> 可选 </td><td> 用一个类似于hadoop-site.xml的XML文件保存所有配置,从而不需要用多个"-jobconf name=value"类型的选项单独为每个配置变量赋值</td></tr> |
| <tr><td> -cmdenv name=value </td><td> 可选 </td><td> 传递环境变量给streaming命令</td></tr> |
| <tr><td> -cacheFile fileNameURI </td><td> 可选 </td><td> 指定一个上传到HDFS的文件</td></tr> |
| <tr><td> -cacheArchive fileNameURI </td><td> 可选 </td><td> 指定一个上传到HDFS的jar文件,这个jar文件会被自动解压缩到当前工作目录下</td></tr> |
| |
| <tr><td> -inputreader JavaClassName </td><td> 可选 </td><td> 为了向下兼容:指定一个record reader类(而不是input format类)</td></tr> |
| <tr><td> -verbose </td><td> 可选 </td><td> 详细输出 </td></tr> |
| </table> |
| <p> |
| 使用-cluster <name>实现“本地”Hadoop和一个或多个远程Hadoop集群间切换。默认情况下,使用hadoop-default.xml和hadoop-site.xml;当使用-cluster <name>选项时,会使用$HADOOP_HOME/conf/hadoop-<name>.xml。 |
| </p> |
| <p> |
| 下面的选项改变temp目录: |
| </p> |
| <source> |
| -jobconf dfs.data.dir=/tmp |
| </source> |
| <p> |
| 下面的选项指定其他本地temp目录: |
| </p> |
| <source> |
| -jobconf mapred.local.dir=/tmp/local |
| -jobconf mapred.system.dir=/tmp/system |
| -jobconf mapred.temp.dir=/tmp/temp |
| </source> |
| <p> |
| 更多有关jobconf的细节请参考:<a href="http://wiki.apache.org/hadoop/JobConfFile">http://wiki.apache.org/hadoop/JobConfFile</a> |
| </p><p> |
| 在streaming命令中设置环境变量: |
| </p> |
| <source> |
| -cmdenv EXAMPLE_DIR=/home/example/dictionaries/ |
| </source> |
| </section> |
| </section> |
| |
| <section> |
| <title>其他例子</title> |
| |
| <section> |
| <title>使用自定义的方法切分行来形成Key/Value对</title> |
| <p> |
| 之前已经提到,当Map/Reduce框架从mapper的标准输入读取一行时,它把这一行切分为key/value对。 |
| 在默认情况下,每行第一个tab符之前的部分作为key,之后的部分作为value(不包括tab符)。 |
| </p> |
| <p> |
| 但是,用户可以自定义,可以指定分隔符是其他字符而不是默认的tab符,或者指定在第n(n>=1)个分割符处分割而不是默认的第一个。例如: |
| </p> |
| |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper org.apache.hadoop.mapred.lib.IdentityMapper \ |
| -reducer org.apache.hadoop.mapred.lib.IdentityReducer \ |
| -jobconf stream.map.output.field.separator=. \ |
| -jobconf stream.num.map.output.key.fields=4 |
| </source> |
| <p> |
| 在上面的例子,“-jobconf stream.map.output.field.separator=.”指定“.”作为map输出内容的分隔符,并且从在第四个“.”之前的部分作为key,之后的部分作为value(不包括这第四个“.”)。 |
| 如果一行中的“.”少于四个,则整行的内容作为key,value设为空的Text对象(就像这样创建了一个Text:new Text(""))。 |
| </p><p> |
| 同样,用户可以使用“-jobconf stream.reduce.output.field.separator=SEP”和“-jobconf stream.num.reduce.output.fields=NUM”来指定reduce输出的行中,第几个分隔符处分割key和value。 |
| </p> |
| </section> |
| |
| |
| <section> |
| <title>一个实用的Partitioner类<!--A Useful Partitioner Class--> (二次排序,-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner 选项) </title> |
| <p> |
| Hadoop有一个工具类org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner, |
| 它在应用程序中很有用。Map/reduce框架用这个类切分map的输出, |
| 切分是基于key值的前缀,而不是整个key。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper org.apache.hadoop.mapred.lib.IdentityMapper \ |
| -reducer org.apache.hadoop.mapred.lib.IdentityReducer \ |
| -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \ |
| -jobconf stream.map.output.field.separator=. \ |
| -jobconf stream.num.map.output.key.fields=4 \ |
| -jobconf map.output.key.field.separator=. \ |
| -jobconf num.key.fields.for.partition=2 \ |
| -jobconf mapred.reduce.tasks=12 |
| </source> |
| <p> |
| 其中,<em>-jobconf stream.map.output.field.separator=.</em> 和<em>-jobconf stream.num.map.output.key.fields=4</em>是前文中的例子。Streaming用这两个变量来得到mapper的key/value对。 |
| </p><p> |
| 上面的Map/Reduce 作业中map输出的key一般是由“.”分割成的四块。但是因为使用了 |
| <em>-jobconf num.key.fields.for.partition=2</em> |
| 选项,所以Map/Reduce框架使用key的前两块来切分map的输出。其中, |
| <em>-jobconf map.output.key.field.separator=.</em> |
| 指定了这次切分使用的key的分隔符。这样可以保证在所有key/value对中, |
| key值前两个块值相同的所有key被分到一组,分配给一个reducer。 |
| </p><p> |
| <em>这种高效的方法等价于指定前两块作为主键,后两块作为副键。 |
| 主键用于切分块,主键和副键的组合用于排序。</em>一个简单的示例如下: |
| </p> |
| <p> |
| Map的输出(key)</p><source> |
| 11.12.1.2 |
| 11.14.2.3 |
| 11.11.4.1 |
| 11.12.1.1 |
| 11.14.2.2 |
| |
| </source> |
| <p> |
| 切分给3个reducer(前两块的值用于切分)</p><source> |
| 11.11.4.1 |
| ----------- |
| 11.12.1.2 |
| 11.12.1.1 |
| ----------- |
| 11.14.2.3 |
| 11.14.2.2 |
| </source> |
| <p> |
| 在每个切分后的组内排序(四个块的值都用于排序) |
| </p><source> |
| 11.11.4.1 |
| ----------- |
| 11.12.1.1 |
| 11.12.1.2 |
| ----------- |
| 11.14.2.2 |
| 11.14.2.3 |
| </source> |
| </section> |
| |
| <section> |
| <title>Hadoop聚合功能包的使用(-reduce aggregate 选项)</title> |
| <p> |
| Hadoop有一个工具包“Aggregate”( |
| <a href="https://svn.apache.org/repos/asf/hadoop/core/trunk/src/java/org/apache/hadoop/mapred/lib/aggregate">https://svn.apache.org/repos/asf/hadoop/core/trunk/src/java/org/apache/hadoop/mapred/lib/aggregate</a>)。 |
| “Aggregate”提供一个特殊的reducer类和一个特殊的combiner类, |
| 并且有一系列的“聚合器”(“aggregator”)(例如“sum”,“max”,“min”等)用于聚合一组value的序列。 |
| 用户可以使用Aggregate定义一个mapper插件类, |
| 这个类用于为mapper输入的每个key/value对产生“可聚合项”。 |
| combiner/reducer利用适当的聚合器聚合这些可聚合项。 |
| </p><p> |
| 要使用Aggregate,只需指定“-reducer aggregate”:</p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper myAggregatorForKeyCount.py \ |
| -reducer aggregate \ |
| -file myAggregatorForKeyCount.py \ |
| -jobconf mapred.reduce.tasks=12 |
| </source> |
| <p> |
| python程序myAggregatorForKeyCount.py例子: |
| </p> |
| <source> |
| #!/usr/bin/python |
| |
| import sys; |
| |
| def generateLongCountToken(id): |
| return "LongValueSum:" + id + "\t" + "1" |
| |
| def main(argv): |
| line = sys.stdin.readline(); |
| try: |
| while line: |
| line = line[:-1]; |
| fields = line.split("\t"); |
| print generateLongCountToken(fields[0]); |
| line = sys.stdin.readline(); |
| except "end of file": |
| return None |
| if __name__ == "__main__": |
| main(sys.argv) |
| </source> |
| </section> |
| |
| <section> |
| <title>字段的选取(类似于unix中的 'cut' 命令) </title> |
| <p> |
| Hadoop的工具类org.apache.hadoop.mapred.lib.FieldSelectionMapReduce帮助用户高效处理文本数据, |
| 就像unix中的“cut”工具。工具类中的map函数把输入的key/value对看作字段的列表。 |
| 用户可以指定字段的分隔符(默认是tab), |
| 可以选择字段列表中任意一段(由列表中一个或多个字段组成)作为map输出的key或者value。 |
| 同样,工具类中的reduce函数也把输入的key/value对看作字段的列表,用户可以选取任意一段作为reduce输出的key或value。例如: |
| </p> |
| <source> |
| $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input myInputDirs \ |
| -output myOutputDir \ |
| -mapper org.apache.hadoop.mapred.lib.FieldSelectionMapReduce\ |
| -reducer org.apache.hadoop.mapred.lib.FieldSelectionMapReduce\ |
| -partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \ |
| -jobconf map.output.key.field.separa=. \ |
| -jobconf num.key.fields.for.partition=2 \ |
| -jobconf mapred.data.field.separator=. \ |
| -jobconf map.output.key.value.fields.spec=6,5,1-3:0- \ |
| -jobconf reduce.output.key.value.fields.spec=0-2:5- \ |
| -jobconf mapred.reduce.tasks=12 |
| </source> |
| <p> |
| 选项“-jobconf map.output.key.value.fields.spec=6,5,1-3:0-”指定了如何为map的输出选取key和value。Key选取规则和value选取规则由“:”分割。 |
| 在这个例子中,map输出的key由字段6,5,1,2和3组成。输出的value由所有字段组成(“0-”指字段0以及之后所有字段)。 |
| </p> |
| <p> |
| 选项“-jobconf reduce.output.key.value.fields.spec=0-2:0-”(译者注:此处应为”0-2:5-“)指定如何为reduce的输出选取value。 |
| 本例中,reduce的输出的key将包含字段0,1,2(对应于原始的字段6,5,1)。 |
| reduce输出的value将包含起自字段5的所有字段(对应于所有的原始字段)。 |
| </p> |
| </section> |
| </section> |
| |
| <section> |
| <title>常见问题</title> |
| |
| <section> |
| <title>我该怎样使用Hadoop Streaming运行一组独立(相关)的任务呢?</title> |
| <p> |
| 多数情况下,你不需要Map Reduce的全部功能, |
| 而只需要运行同一程序的多个实例,或者使用不同数据,或者在相同数据上使用不同的参数。 |
| 你可以通过Hadoop Streaming来实现。</p> |
| |
| </section> |
| |
| <section> |
| <title>如何处理多个文件,其中每个文件一个map?</title> |
| <p> |
| 例如这样一个问题,在集群上压缩(zipping)一些文件,你可以使用以下几种方法:</p><ol> |
| <li>使用Hadoop Streaming和用户编写的mapper脚本程序:<ul> |
| <li> 生成一个文件,文件中包含所有要压缩的文件在HDFS上的完整路径。每个map 任务获得一个路径名作为输入。</li> |
| <li> 创建一个mapper脚本程序,实现如下功能:获得文件名,把该文件拷贝到本地,压缩该文件并把它发到期望的输出目录。</li> |
| </ul></li> |
| <li>使用现有的Hadoop框架:<ul> |
| <li>在main函数中添加如下命令: |
| <source> |
| FileOutputFormat.setCompressOutput(conf, true); |
| FileOutputFormat.setOutputCompressorClass(conf, org.apache.hadoop.io.compress.GzipCodec.class); |
| conf.setOutputFormat(NonSplitableTextInputFormat.class); |
| conf.setNumReduceTasks(0); |
| </source></li> |
| <li>编写map函数: |
| <source> |
| |
| public void map(WritableComparable key, Writable value, |
| OutputCollector output, |
| Reporter reporter) throws IOException { |
| output.collect((Text)value, null); |
| } |
| </source></li> |
| <li>注意输出的文件名和原文件名不同</li> |
| </ul></li> |
| </ol> |
| </section> |
| |
| <section> |
| <title>应该使用多少个reducer?</title> |
| <p> |
| 请参考Hadoop Wiki:<a href="mapred_tutorial.html#Reducer">Reducer</a> |
| </p> |
| </section> |
| |
| <section> |
| <title> |
| 如果在Shell脚本里设置一个别名,并放在-mapper之后,Streaming会正常运行吗? |
| 例如,alias cl='cut -fl',-mapper "cl"会运行正常吗? |
| </title> |
| <p> |
| 脚本里无法使用别名,但是允许变量替换,例如: |
| </p> |
| <source> |
| $ hadoop dfs -cat samples/student_marks |
| alice 50 |
| bruce 70 |
| charlie 80 |
| dan 75 |
| |
| $ c2='cut -f2'; $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \ |
| -input /user/me/samples/student_marks |
| -mapper \"$c2\" -reducer 'cat' |
| -output /user/me/samples/student_out |
| -jobconf mapred.job.name='Experiment' |
| |
| $ hadoop dfs -ls samples/student_out |
| Found 1 items/user/me/samples/student_out/part-00000 <r 3> 16 |
| |
| $ hadoop dfs -cat samples/student_out/part-00000 |
| 50 |
| 70 |
| 75 |
| 80 |
| </source> |
| </section> |
| |
| <section> |
| <title> |
| 我可以使用UNIX pipes吗?例如 –mapper "cut –fl | set s/foo/bar/g"管用么? |
| </title> |
| <p> |
| 现在不支持,而且会给出错误信息“java.io.IOException: Broken pipe”。这或许是一个bug,需要进一步研究。 |
| </p> |
| </section> |
| |
| <section> |
| <title>在streaming作业中用-file选项运行一个<strong>分布式的超大可执行文件(例如,3.6G)</strong>时, |
| 我得到了一个错误信息“No space left on device”。如何解决? |
| </title> |
| <p> |
| 配置变量stream.tmpdir指定了一个目录,在这个目录下要进行打jar包的操作。stream.tmpdir的默认值是/tmp,你需要将这个值设置为一个有更大空间的目录: |
| </p> |
| <source> |
| -jobconf stream.tmpdir=/export/bigspace/... |
| </source> |
| </section> |
| |
| <section> |
| <title>如何设置多个输入目录?</title> |
| <p> |
| 可以使用多个-input选项设置多个输入目录: |
| </p><source> |
| hadoop jar hadoop-streaming.jar -input '/user/foo/dir1' -input '/user/foo/dir2' |
| </source> |
| </section> |
| |
| <section> |
| <title>如何生成gzip格式的输出文件?</title> |
| <p> |
| 除了纯文本格式的输出,你还可以生成gzip文件格式的输出,你只需设置streaming作业中的选项‘-jobconf mapred.output.compress=true -jobconf mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCode’。 |
| </p> |
| </section> |
| |
| <section> |
| <title>Streaming中如何自定义input/output format?</title> |
| <p> |
| 至少在Hadoop 0.14版本以前,不支持多个jar文件。所以当指定自定义的类时,你要把他们和原有的streaming jar打包在一起,并用这个自定义的jar包替换默认的hadoop streaming jar包。 |
| </p> |
| </section> |
| |
| <section> |
| <title>Streaming如何解析XML文档?</title> |
| <p> |
| 你可以使用StreamXmlRecordReader来解析XML文档。 |
| </p> |
| <source> |
| hadoop jar hadoop-streaming.jar -inputreader "StreamXmlRecord,begin=BEGIN_STRING,end=END_STRING" ..... (rest of the command) |
| </source> |
| <p> |
| Map任务会把BEGIN_STRING和END_STRING之间的部分看作一条记录。 |
| </p> |
| </section> |
| |
| <section> |
| <title>在streaming应用程序中如何更新计数器?</title> |
| <p> |
| streaming进程能够使用stderr发出计数器信息。 |
| <code>reporter:counter:<group>,<counter>,<amount></code> |
| 应该被发送到stderr来更新计数器。 |
| </p> |
| </section> |
| <section> |
| <title>如何更新streaming应用程序的状态?</title> |
| <p> |
| streaming进程能够使用stderr发出状态信息。 |
| <code>reporter:status:<message></code> 要被发送到stderr来设置状态。 |
| </p> |
| </section> |
| |
| </section> |
| </body> |
| </document> |