在值上迭代两次(MapReduce)

log*_*og0 18 java hadoop iterator

我收到一个迭代器作为参数,我想迭代两次值.

public void reduce(Pair<String,String> key, Iterator<IntWritable> values,
                   Context context)
Run Code Online (Sandbox Code Playgroud)

可能吗 ?怎么样 ?签名是由我正在使用的框架(即Hadoop)强加的.

- 编辑 -
最后方法的真实签名reduceiterable.我被这个wiki页面误导了(这实际上是我发现的wordcount的唯一非弃用(但错误的)示例).

ajd*_*574 14

不幸的是,如果不按照Andreas_D的回答缓存值,这是不可能的.

即使使用新的API,Reducer接收Iterable而不是一个Iterator,你不能迭代两次.尝试类似以下内容非常诱人:

for (IntWritable value : values) {
    // first loop
}

for (IntWritable value : values) {
    // second loop
}
Run Code Online (Sandbox Code Playgroud)

但这实际上不起作用.在Iterator您从收到Iterableiterator()方法很特别.这些值可能并非都在内存中; Hadoop可能正在从磁盘流式传输它们.它们并非真正由a支持Collection,因此允许多次迭代是非常重要的.

你可以在ReducerReduceContext代码中看到这个.

Collection以某种方式缓存值可能是最简单的答案,但如果您在大型数据集上操作,则可以轻松地将堆清除.如果您可以就问题提供更多详细信息,我们可以帮助您找到不涉及多次迭代的解决方案.


aka*_*ppa 10

重用给定的迭代器,没有.

但是当你在第一个位置迭代它们然后迭代构造的ArrayList时,你可以将值保存在ArrayList中(或者你可以通过使用一些花哨的Collection方法直接在它上面构建它,然后直接在ArrayList两次.这是一个品味问题).

无论如何,你确定首先通过Iterator是一件好事吗?迭代器习惯于通过集合进行线性扫描,这就是他们不公开"倒带"方法的原因.

你应该传递一些不同的东西,比如a Collection<T>或an Iterable<T>,就像在另一个答案中已经建议的那样.


And*_*s_D 10

如果要再次迭代,我们必须缓存迭代器中的值.至少我们可以结合第一次迭代和缓存:

Iterator<IntWritable> it = getIterator();
List<IntWritable> cache = new ArrayList<IntWritable>();

// first loop and caching
while (it.hasNext()) {
   IntWritable value = it.next();
   doSomethingWithValue();
   cache.add(value);
}

// second loop
for(IntWritable value:cache) {
   doSomethingElseThatCantBeDoneInFirstLoop(value);
}
Run Code Online (Sandbox Code Playgroud)

(只是用代码添加答案,知道你在自己的评论中提到了这个解决方案;))


为什么没有缓存Iterator是不可能的:一个实现接口的东西,没有一个要求,Iterator对象实际存储值.迭代两次你必须重置迭代器(不可能)或克隆它(再次:不可能).

举一个迭代器的例子,其中克隆/重置没有任何意义:

public class Randoms implements Iterator<Double> {

  private int counter = 10;

  @Override 
  public boolean hasNext() { 
     return counter > 0; 
  }

  @Override 
  public boolean next() { 
     count--;
     return Math.random();        
  }      

  @Override 
  public boolean remove() { 
     throw new UnsupportedOperationException("delete not supported"); 
  }
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*ung 6

迭代器只是一次遍历.某些迭代器类型是可复制的,您可以在遍历之前克隆它,但这不是一般情况.

你应该让你的功能Iterable取而代之,如果你能做到的话.