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)强加的.
- 编辑 -
最后方法的真实签名reduce是iterable.我被这个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您从收到Iterable的iterator()方法很特别.这些值可能并非都在内存中; Hadoop可能正在从磁盘流式传输它们.它们并非真正由a支持Collection,因此允许多次迭代是非常重要的.
你可以在Reducer和ReduceContext代码中看到这个.
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)