如何在hadoop的shuffle / sort阶段进行数字排序?

时间:2012-11-11 13:52:08

标签: sorting hadoop

数据看起来像这样,第一个字段是数字,

3 ...
1 ...
2 ...
11 ...

我想根据第一个字段而不是按字母顺序对这些行进行排序,这意味着在排序后它应该看起来像这样,

1 ...
2 ...
3 ...
11 ...

但是hadoop一直在给我这个,

1 ...
11 ...
2 ...
3 ...

如何纠正?

3 个答案:

答案 0 :(得分:22)

假设您使用 Hadoop Streaming ,则需要使用 KeyFieldBasedComparator 类。

  1. -D mapred.output.key.comparator.class = org.apache.hadoop.mapred.lib.KeyFieldBasedComparator应添加到流媒体命令

  2. 您需要使用mapred.text.key.comparator.options提供所需的排序类型。一些有用的是-n:数字排序,-r:反向排序

  3. 示例

    使用以下代码创建身份映射器和reducer

    这是 mapper.py & reducer.py

    #!/usr/bin/env python
    import sys
    for line in sys.stdin:    
        print "%s" % (line.strip())
    

    这是 input.txt

    1
    11
    2
    20
    7
    3
    40
    

    这是 Streaming 命令

    $HADOOP_HOME/bin/hadoop  jar $HADOOP_HOME/hadoop-streaming.jar 
    -D mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator 
    -D  mapred.text.key.comparator.options=-n 
    -input /user/input.txt 
    -output /user/output.txt 
    -file ~/mapper.py 
    -mapper ~/mapper.py 
    -file ~/reducer.py 
    -reducer ~/reducer.py
    

    您将获得所需的输出

    1   
    2   
    3   
    7   
    11  
    20  
    40
    

    注意

    1. 我使用了一个简单的一键输入。但是,如果您有多个键和/或分区,则必须根据需要编辑mapred.text.key.comparator.options。由于我不知道您的用例,我的示例仅限于此

    2. 需要身份映射器,因为您需要至少一个映射器才能运行MR作业。

    3. 需要身份缩减器,因为如果它只是纯粹的地图作业,则无法使用随机播放/排序阶段。

答案 1 :(得分:7)

Hadoop的默认比较器会根据您使用的Writable类型(更准确地说是WritableComparable)来比较您的密钥。如果您正在处理IntWritableLongWritable,那么它会按数字对它们进行排序。

我假设您在示例中使用的是Text,因此您最终会获得自然排序顺序

但是,在特殊情况下,您也可以编写自己的比较器 例如:仅用于测试目的,这里有一个快速示例如何更改文本键的排序顺序:这会将它们视为整数并生成数字排序顺序:

public class MyComparator extends WritableComparator {

        public MyComparator() {
            super(Text.class);
        }

        @Override
        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {

            try {

                String v1 = Text.decode(b1, s1, l1);
                String v2 = Text.decode(b2, s2, l2);

                int v1Int = Integer.valueOf(v1.trim());
                int v2Int = Integer.valueOf(v2.trim());

                return (v1Int < v2Int) ? -1 : ((v1Int > v2Int) ? 1 : 0);

            }
            catch (IOException e) {
                throw new IllegalArgumentException(e);
            }
        }
    }

在jobrunner类集中:

Job job = new Job();
...
job.setSortComparatorClass(MyComparator.class);

答案 2 :(得分:0)

对于使用订单Hadoop进行流式传输(可使用-jobconf而非-D进行配置),可以按键进行排序:

-jobconf stream.num.map.output.key.fields=2\
-jobconf mapreduce.partition.keycomparator.options="-k2,2nr"\
-jobconf mapred.output.key.comparator.class=org.apache.hadoop.mapred.lib.KeyFieldBasedComparator

根据stream.num.map.output.key.fields,第一列和第二列分别为key 1key 2

mapreduce.partition.keycomparator.options="-k2,2nr"表示通过使用第二个键(从第二个键到第二个键)作为数值以相反的顺序进行排序。

这非常类似于Linux sort命令!