为了有效地处理这个问题,每个reducer应该获得一些高音量键或许多低音量键,以便获得大致均匀的负载.如果我正在编写分区进程,我知道如何执行此操作:我将获取由映射器生成的键的排序列表(包括所有重复键)以及减少器的数量N和放置拆分
split[i] = keys[floor(i*len(keys)/N)]
减速器我将获得密钥k,使得split [i]< = k< split [i 1] for 0< = i<对于i == N-1,N-1和split [i]< = k. 我愿意用Java编写自己的分区器,但Partitioner<KEY,VALUE>类似乎一次只能访问一个键值记录,而不是整个列表.我知道Hadoop会对映射器生成的记录进行排序,因此该列表必须存在于某处.它可能分布在多个分区节点之间,在这种情况下,我会在其中一个子列表上执行拆分过程,并以某种方式将结果传递给所有其他分区节点. (假设所选分区器节点看到一个随机化子集,结果仍然是近似负载平衡的.)有没有人知道存储密钥的排序列表的位置,以及如何访问它?
我不想编写两个map-reduce作业,一个用于查找拆分,另一个用于实际使用它们,因为这看起来很浪费. (地图制作者必须做两次相同的工作.)这似乎是一个普遍的问题:不均匀的分布很常见.
解决方法
>除了用于解决业务问题的映射器逻辑之外,还要编写一些逻辑来收集分区器中需要的任何统计信息,以便以平衡的方式分配键值对.当然,每个映射器只会看到一些数据.
>每个映射器都可以找到其任务ID,并使用该ID在指定的hdfs文件夹中构建唯一的文件名,以保存收集的统计信息.将此文件写入在任务结束时运行的cleanup()方法中.
>在分区程序中使用延迟初始化来读取指定hdfs目录中的所有文件.这将为您提供在映射器阶段收集的所有统计信息.从那里开始,您将实现正确分区数据所需的任何分区逻辑.
这一切都假设在所有映射器完成之前不会调用分区器,但这是迄今为止我能够做到的最好的.