4

我对 hadoop 流非常陌生,并且在分区方面遇到了一些困难。

根据在一行中找到的内容,我的映射器函数要么返回

key1, 0, somegeneralvalues # some kind of "header" line where linetype = 0

或者

key1, 1, value1, value2, othervalues... # "data" line, different values, linetype =1

为了正确减少,我需要对具有相同key1的所有行进行分组,并按 value1、value2 和线型(0 或 1)对它们进行排序,例如:

1 0 foo bar...  # header first
1 1 888 999.... # data line, with lower value1
1 1 999 111.... # a few datalines may follow. Sort by value1,value2 should be performed
------------    #possible partition here, and only here in this example
2 0 baz foobar....   
2 1 123 888... 
2 1 123 999...
2 1 456 111...  

有没有办法确保这样的分区?到目前为止,我已经尝试过使用诸如

-partitioner,'org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner'
-D stream.num.map.output.key.fields=4 # please use 4 fields to sort data
-D mapred.text.key.partitioner.options=-k1,1 # please make partitions based on first key

或者

-D num.key.fields.for.partition=1 # Seriously, please group by key1 !

但这只会带来愤怒和绝望。

如果值得一提,如果我使用cat 数据,我的脚本可以正常工作 | 映射器 | 排序 | 减少 ,我正在使用亚马逊弹性地图减少红宝石客户端,所以我将选项传递给

--arg '-D','options' for the ruby script.

任何帮助将不胜感激!提前致谢

4

2 回答 2

3

感谢 ryanbwork,我已经能够解决这个问题。耶 !

正确的想法确实是创建一个由值串联组成的键。更进一步,还可以创建一个看起来像

<'1.0.foo.bar', {'0','foo','bar'}>
<'1.1.888.999', {'1','888','999'}>

然后可以将选项传递给hadoop,以便它可以按密钥的第一个“部分”进行分区。如果我没记错的话,它看起来像

-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartioner
-D stream.map.output.field.separator=. # I added some "." in the key
-D stream.num.map.output.key.fields=4  # 4 "sub-fields" are used to sort
-D num.key.fields.for.partition=1      # only one field is used to partition

这个解决方案,基于 ryanbwork 所说的,允许创建更多的 reducer,同时确保数据被正确拆分和排序。

于 2013-01-29T10:24:09.890 回答
2

阅读完这篇文章后,我建议修改您的映射器,使其返回“键”包括您的键值、线型值和 value1/value2 值全部连接在一起的对。您将保持该对的“价值”部分相同。因此,例如,您将返回以下对来表示您的前两个示例:

<'10foobar',{'0','foo','bar'}>
<'11888999',{'1','888','999'}>

现在,如果您要使用单个 reducer,您的所有记录都将被发送到同一个 reduce 任务,并根据它们的“键”按字母顺序排序。这将满足您的要求,即对按键排序,然后按线型排序,然后按 value1,最后按 value2,您可以在对的“值”部分单独访问这些值。我对不同的内置分区器/排序类不是很熟悉,但我假设你可以只使用默认值并让它工作。

于 2013-01-28T23:38:11.370 回答