接上篇:hadoop全局排序
本篇通过设置partitioner,多个reducer来实现全局排序。
这里的思路一个partition对应一个reduce的task,reduce的输入本来就是对key有序的,所以很自然地就产生了一个排序文件,如果是分多个partition呢,则只要确保partition是有序的就行了。
比如我们的数据是这样的 aaa bbb ccc
我们设定key=aaa bbb , 则value=ccc。
再设定partition=aaa。
也就是先按照第一列数据进行分桶,然后每个分桶里面的数据再按照key进行sort,相当于做了二次排序这么一个事情。
接着用上篇的例子进行解释:
我们数据是0-100个数据,我们设定reduce num = 2;
我们希望0-49放在reduce1中,50-100放入reduce2中。通过一个支点来判断左右,将数据放入两个particular中。
代码:
import sys
base_count = 10000
for line in sys.stdin:
ss = line.strip().split('\t')
key = ss[0]
val = ss[1]
new_key = base_count + int(key)
red_idx = 1
if new_key < (10100 + 10000) / 2:#判断并将数据分为两个桶
red_idx = 0
print "%s\t%s\t%s"% (red_idx, new_key, val)
通过map阶段以后的数据变成三个字段。
red.py:#reduce阶段只需要获取key & value 即可
import sys
base_count = 10000
for line in sys.stdin:
idx_id, key, val = line.strip().split('\t')
new_key = int(key)-base_count
print '\t'.join([str(new_key), val])
如果要本地模拟的话命令如下:
cat a.txt b.txt | python map_sort.py | sort -k2 | sort -k1 | python red_sort.py #需要先对第二列排序,再对第一列排序
也就是每一个partitioner中的数据先排序,再将partition进行排序,最后数据扔给reduce。
关键设置在run.sh里面:
多了如下几行代码:
-jobconf mapred.reduce.tasks=2 \#设置reduce num
-jobconf stream.num.map.output.key.fields=2 \#key=第二列,sort是按照key进行的。
-jobconf num.key.fields.for.partition=1 \#按第一列分区partition
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner
至此,代码完成。集群运行下看结果如何。
bash run.sh
可以看到结果有两个part
0-49个数据落在了part-00000中:
50-100的数据落在了part-00001中:
再举一个稍微复杂的例子:
数据如下:
d.1.5.23
e.9.4.5
e.5.9.22
e.5.1.45
e.5.1.23
a.7.2.6
f.8.3.3
run.sh代码如下:
HADOOP_CMD="/usr/local/src/hadoop-2.6.1/bin/hadoop"
STREAM_JAR_PATH="/usr/local/src/hadoop-2.6.1/share/hadoop/tools/lib/hadoop-streaming-2.6.1.jar"
INPUT_FILE_PATH_A="/aaa.txt"
OUTPUT_SORT_PATH="/output_sort"
$HADOOP_CMD fs -rmr -skipTrash $OUTPUT_SORT_PATH
# Step 3.
$HADOOP_CMD jar $STREAM_JAR_PATH \
-input $INPUT_FILE_PATH_A \
-output $OUTPUT_SORT_PATH \
-mapper "cat" \#使用cat即可
-reducer "cat" \#使用cat即可
-jobconf stream.num.map.output.key.fields=3 \
-jobconf stream.map.output.field.separator=. \
-jobconf map.output.key.field.separator=. \
-jobconf mapred.text.key.partitioner.options=-k2,3 \
-jobconf mapred.reduce.tasks=3
key = 前3列字段
按照字符.分割
partitioner=2和3字段
reduce num = 3
运行结果:
三个part:
结果如下:
END!
谢谢阅读!
欢迎关注:【大数据学习笔记】个人公众号,一起交流学习!