我试图使用hadoop找到任何给定点的总和,我遇到的问题是从单个reducer中获取给定键的所有值.看起来像这样.
减速器:
public static class Reduce extends MapReduceBase implements Reducer{ public void reduce(Text key, Iterator values, OutputCollector output, Reporter reporter) throws IOException { Text word = new Text(); Iterator tr = values; IntWritable v; while (tr.hasNext()) { v = tr.next(); Iterator td = values; while (td.hasNext()) { IntWritable u = td.next(); double sum = u+v; word.set( u + " + " + v); output.collect(word, new DoubleWritable(sum)); } } } }
我试图创建Iterator变量的两个副本,以便我可以通过第二个迭代器的所有值,而我从前一个迭代器获取单个值(两个while循环),但两个迭代器保持相同的值所有时间.
我不确定这是否是正确的方法,任何帮助都非常感谢.
谢谢,
Tsegay
减速器中的迭代器并不像您想象的那么简单.
问题是您迭代的项目总数可能不适合内存.这意味着迭代器可能正在从磁盘读取.如果你有两个独立的迭代器副本,那么你可以让它们中的一个远远超过另一个,这意味着两个迭代器指向的数据之间的数据不能被删除.
为简化实现,Hadoop不支持为reduce值使用多个迭代器.
这样做的实际影响是你不能两次通过相同的迭代器.这不好,但情况确实如此.如果您完全知道项目的数量将适合内存,那么您可以按照MrGomez的建议将所有项目复制到列表中.如果您不知道,则可能必须使用二级存储.
更好的方法是重新设计程序,以便在reducer中不需要无限存储.这可能有点棘手,但有问题的标准方法.
对于您的特定问题,相对于最大减少输入集,输出大小会呈二次增长.这通常是一个非常糟糕的主意.在大多数情况下,您不需要所有对,只需要最重要的对.如果您可以以某种方式修剪对的集合,那么您已经设置好了,并且您可以删除所有对约束.
例如,如果您尝试查找每个reduce集合中具有最大总和的100对,则可以保留具有到目前为止看到的100个最大输入的优先级队列以及到目前为止看到的具有100个最大总和的优先级队列.对于每个新输入,您可以形成目前为止看到的最大100个数字的总和,并尝试将这些总和粘贴到第二个队列中.最后,您应该将新输入粘贴到第一个队列中,并通过删除最小值(如果需要)将两个队列修剪为100个元素.在reduce的close方法中,您应该转储优先级队列.这种方法保证您只需要min(n ^ 2,200)个存储元素,避免了n ^ 2问题,并通过保持看到的100个最大项而不是所有看到的项来避免双重通过输入.
我不确定你要完成什么,但我知道的很多:Hadoop迭代器的行为有点奇怪.调用Iterator.next()将始终返回IntWritable的SAME EXACT实例,该实例的内容将替换为下一个值.因此,在对Iterator.next()的调用中保持对IntWritable的引用几乎总是一个错误.我相信这种行为是设计用于减少对象创建量和GC开销.
解决此问题的一种方法是使用WritableUtils.clone()克隆您尝试在Iterator.next()调用期间保留的实例.