我对hadoop流非常新,并且在分区方面遇到了一些困难。
根据行中的内容,我的mapper函数返回
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和linetype(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 data |,我的脚本就能正常工作映射器|排序|减少的 我正在使用亚马逊弹性地图减少ruby客户端,所以我用
传递选项--arg '-D','options' for the ruby script.
任何帮助都将受到高度赞赏!提前致谢
答案 0 :(得分: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,同时确保数据被正确分割和排序。
答案 1 :(得分:2)
在阅读this post之后,我建议修改您的映射器,使其返回其“键”包括键值,线型值和值1 /值2值的对,它们连接在一起。你保持对的“价值”部分是一样的。例如,您将返回以下对来代表前两个示例:
<'10foobar',{'0','foo','bar'}>
<'11888999',{'1','888','999'}>
现在,如果您要使用单个reducer,您的所有记录都将被发送到同一个reduce任务,并根据其“key”按字母顺序排序。这将满足您的要求,即按键,然后按行类型,然后按值1和最后的值2进行排序,您可以在对的“值”部分中单独访问这些值。我不太熟悉不同的内置分区/排序类,但我假设您可以使用默认值并使其工作。