あなたは本を正しく読んでいます。レデューサーはすべての値をメモリに格納するわけではありません。代わりに、Iterable 値リストをループすると、各 Object インスタンスが再利用されるため、一度に 1 つのインスタンスだけが維持されます。
たとえば、次のコードでは、objs ArrayList はループ後に予想されるサイズになりますが、すべての要素は同じになります。b/c Text val インスタンスは反復ごとに再利用されます。
public static class ReducerExample extends Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterable<Text> values, Context context) {
ArrayList<Text> objs = new ArrayList<Text>();
for (Text val : values){
objs.add(val);
}
}
}
(何らかの理由で各 val に対してさらにアクションを実行したい場合は、ディープ コピーを作成してから保存する必要があります。)
もちろん、単一の値でもメモリよりも大きくなる可能性があります。この場合、開発者は、値がそれほど大きくならないように、前の Mapper でデータを切り詰める手順を実行することをお勧めします。
更新: Hadoop The Definitive Guide 2nd Edition の 199 ~ 200 ページを参照してください。
This code snippet makes it clear that the same key and value objects are used on each
invocation of the map() method -- only their contents are changed (by the reader's
next() method). This can be a surprise to users, who might expect keys and vales to be
immutable. This causes prolems when a reference to a key or value object is retained
outside the map() method, as its value can change without warning. If you need to do
this, make a copy of the object you want to hold on to. For example, for a Text object,
you can use its copy constructor: new Text(value).
The situation is similar with reducers. In this case, the value object in the reducer's
iterator are reused, so you need to copy any that you need to retain between calls to
the iterator.