1/Streaming的作用
<1>Hadoop Streaming框架,最大的好处是:
可以让任何语言编写的map,reduce程序在hadoop集群上运行
<2>map/reduce程序只要遵循从标准输入stdin读取数据,写出到标准输出stdout即可
<3>其次,容易进行单机调试,通过管道符前后相接的方式就可以模拟streaming,
在本地完成map/reduce程序的调试
cat inputfile | mapper | sort | reducer > output
<4>最后,streaming框架还提供了作业job提交时的丰富参数控制,
直接通过streaming参数,而不需要使用java语言修改;
很多mapreduce的高阶功能,都可以通过steaming参数的设置和调整来完成。
2/Streaming的局限
<1>Streaming默认只能处理文本数据Textfile,
对于二进制数据,比较好的方法是将二进制的key, value进行base64编码,转化为文本
<2>Mapper和reducer的前后都要进行标准输入和标准输出的转化,涉及数据拷贝和解析,带来了一定的开销
3/Streaming命令的形式
hadoop jar hadoop_streaming.jar [普通选项] [Streaming选项]
注意:普通选项一定要写在[streaming选项]前面
4/普通选项有哪些
参考网址: https://www.cnblogs.com/shay-zhangjin/p/7714868.html
-D 普通选项,使用最多的高级参数,替代-jobconf(参数将被废弃),需要注意的是 -D选项要放在streaming参数的前面
-D mapred.job.name="Test001"
-D mapred.map.tasks=2
-D mapred.reduce.tasks=2
-D mapred.reduce.tasks=0
-D stream.map.output.field.separator=.
-D stream.num.map.output.key.fields=4
指定Mapper输出的key,value分隔符
Mapper的输出使用.做分割符,并且第4个.之前的部分作为key, 剩余的部分作为value (包含剩余的.)
如果mapper的输出没有4个., 则整体一行作为key, value为空
默认情况下:使用\t做分隔符,第1个\t之前的部分作为key, 剩余为value, 如果mapper输出没有\t,则整体一行作为key,value为空
-D stream.reduce.output.field.seperator=.
-D stream.num.reduce.output.key.fields=4
指定reduce输出根据.分割,第4个.之前的内容为key,其他为value
Reducer程序要根据指定进行key,value的构造,不像map那样有默认情况
-D mapred.job.priority=HIGH
-D mapred.job.map.capacity=5
-D mapred.job.reduce.capacity=3
-D mapred.task.timeout=6000
指定列数,partition分桶
-D num.key.fields.for.partition=1
-D num.key.fields.for.partition=2
指定某些字段做key
-D mapred.text.key.partitioner.option =-k1,2
-D mapred.text.key.partitioner.option =-k2,2
-D mapreduce.reduce.memory.mb=512
5/streaming选项
-input
-output
-mapper
-reducer
-file
6/Mapper输入/输出,根据哪些key分桶,根据哪些key进行排序
Mapper输入:
每一个mapper开始运行时,输入文件会被转换成多行(TextInputformat根据\n来进行分行),并将每一行传递给stdin, 作为Mapper的输入, mapper直接对stdin中的每行内容做处理
Mapper输出分隔符:
默认情况下hadoop设置mapper输出的key, value通过tab进行分隔,可以重新指定
-D stream.map.output.field.seperator=.
-D stream.num.map.output.key.fields=4
Mapper的输出会经历:
1、 partition前,根据mapper输出分隔符分离出Key和Value;
-D stream.map.output.field.separator=.
-D stream.num.map.output.key.fields=4
-D map.output.key.field.separator=.
2、 根据 “分桶分隔符”,确定哪些key被用来做partition(默认是用所有key, 只有1列
基于指定的Key进行分桶,打标签
指定列数
-D num.key.fields.for.partition=1
-D num.key.fields.for.partition=2
Reducer的输入:
每个Reducer的每条输入,就是去除Partition标签(根据Mapper分隔符分离出partition标签)后的内容,和Mapper输出到stdout中的内容相同,但不同记录之间已经做了排序;因此如果重新指定了Mapper的输出分隔符,Reducer程序就要修改为根据新的Mapper输出分隔符来分离Key,value
Reducer的输出:
Reducer的输出,默认也是根据tab来分离key,value, 这也是reducer程序要根据tab来组合key,value输出给stdout的原因; 当Reducer输出分隔符重新指定,Reducer程序中输出给stdout的内容也要配合新的分隔符来构造(Reducer->stdout-> outputformat ->file, outputformat根据reducer的输出分隔符来分离key,value, 并写入文件)
-D stream.reduce.output.field.seperator=.
-D stream.num.reduce.output.key.fields=4
7/hadoop集群执行python脚本
首先在本地把文件上传到hdfs分布式文件存储系统
hdfs dfs -put test.txt /user_hadoop/houzhen03/input
在集群上执行hadoop任务:
hadoop jar hadoop_streaming.jar -input 输入文件 -output 输出文件存放的目录 -mapper "python mapper.py" -reducer 'python reducer.py' -file /home/hadoop/mapper.py -file /home/hadoop/rreducer.py
-file一定是绝对路径
作业完成之后,查看输出结果:
hdfs dfs -cat 输出文件存放的目录/part-00000
8/ hadoop脚本
import os
hadoop_path = "/home/hadoop/hadoop-2.9.2/bin/hadoop jar "
hadoop_streaming_path = " /home/hadoop/hadoop-2.9.2/share/hadoop/tools/lib/hadoop-streaming-2.9.2.jar "
input_path = " /user_hadoop/houzhen03/input/1.txt "
或者 input_path = " /user_hadoop/houzhen03/input "
output_path = " /user_hadoop/houzhen03/output/999 "
def main(input_path,output_path):
command = hadoop_path + hadoop_streaming_path + \
" -input " + input_path + \
" -output " + output_path + \
" -mapper \'python mapper.py\'" + \
" -reducer \'python reducer.py\'" + \
" -file /home/hadoop/mapper.py" + \
" -file /home/hadoop/reducer.py"
os.system(command)
main(input_path,output_path)