我有一个流式地图缩减作业。我有大约 30 个插槽要处理。最初,我得到一个包含 60 条记录的输入文件(字段以制表符分隔),每条记录的第一个字段是一个数字,对于第一个记录编号(第一个字段)是 1,对于第二个记录编号(第一个字段)是 2,依此类推。我想从这些记录中创建 30 个文件以进行下一步处理,每个文件包含 2 条记录(均匀分布)。
为此,我将 hadoop 作业的化简器数量指定为 30。我希望第一个字段将用作键,我将获得 30 个输出文件,每个文件包含 2 条记录。
我确实得到了 30 个输出文件,但并非所有文件都包含相同数量的记录。有些文件甚至是空的(零大小)。任何想法
Hadoop 默认将映射任务输出组合为Reducer输入。所以映射输出集具有相同的键值映射到相同的 reducer.so 通过这样做,某些化简器可能没有输入集,因此假设 part-00005 文件的大小为 0 KB。
您的输出密钥类型是什么?如果您使用的是文本而不是 IntWritable(我假设您必须在使用流式处理时这样做),那么减少数是根据表示键值的 UTF-8 "字符串"的字节表示的哈希值计算的。您可以编写一个简单的单元测试来观察这一点:
public class TextHashTest {
@Test
public void testHash() {
int partitions = 30;
for (int x = 0; x < 100; x++) {
int hash = new Text(String.valueOf(x)).hashCode();
int part = hash % partitions;
System.err.printf("%d = %d => %dn", x, hash, part);
}
}
}
我不会粘贴输出,但在 100 个值中,分区箱 0-7 永远不会收到任何值。
所以就像 Thomas Jungblut 在他的评论中所说的那样,你需要编写一个自定义分区程序来将 Text 值转换回整数值,然后将这个数字取模分区总数 - 但如果值本身不在 1 上序列中,这可能仍然不会给你"均匀"分布(你说它们是这样你应该没问题)
public class IntTextPartitioner implements Partitioner<Text, Text> {
public void configure(JobConf job) {}
public int getPartition(Text key, Text value, int numPartitions) {
return Integer.valueOf(key.toString()) % numPartitions;
}
}