La classe Reducer

Dopo l'ordinamento e la ridistribuzione dei dati intermedi, tutti i valori associati alla stessa chiave vengono elaborati da un unico riduttore (la stessa istanza della classe Reducer), In genere, il riduttore aggrega i valori dati a un risultato finale. Il numero di riduzioni è determinato dalla distribuzione dei dati intermedi. Cioè, il framework lancia un task di riduzione su ogni dataslice.

<K2, listaV2)>* → Riduttore → <K3, V3>*

L'implementazione del riduttore consiste in quattro metodi: setup(), reduce(), cleanup() e run(). Per impostazione predefinita, il metodo run() richiama una volta il metodo setup(), poi il metodo reduce() per ogni coppia <chiave, (elenco di valori)> e infine il metodo cleanup(). Ad esempio:
public void run(Context context) throws IOException,
InterruptedException {
setup(context);
while (context.nextKey()) {
reduce(context.getCurrentKey(), context.getValues(), context);
}
cleanup(context);
}

Il metodo reduce(), per impostazione predefinita, emette il suo input come output, agendo come una funzione di identità, e deve essere sovrascritto. (È possibile sovrascrivere uno qualsiasi di questi metodi, compreso run() per casi d'uso avanzati)

L'oggetto contesto per il riduttore

Il riduttore ha accesso all'oggetto contesto, che gli consente di interagire con il resto dell'ambiente. L'oggetto context, passato come argomento al riduttore e ad altri metodi, fornisce l'accesso ai dati di configurazione del lavoro e consente al riduttore di emettere coppie di output usando il metodo Context.write(key, value).

Il metodo Context.getConfiguration() restituisce un oggetto di configurazione contenente i dati di configurazione di un programma map/reduce in esecuzione. È possibile impostare coppie arbitrarie (chiave, valore) di dati di configurazione nel lavoro (ad esempio con il metodo Job.getConfiguration().set("myKey", "myVal")) e quindi recuperare questi dati nel riduttore con il metodo Context.getConfiguration().get("myKey"). (Questo viene fatto in genere nel metodo setup() del riduttore)

Il metodo cleanup() è principalmente sovrascrivibile (per impostazione predefinita non avviene alcuna pulizia). Se è necessario eseguire la pulizia dopo che tutti gli input sono stati elaborati, è possibile sovrascrivere il valore predefinito e impostarlo in base al caso d'uso specifico.

Non è necessario definire una classe di riduttori per il lavoro. Se non si definisce una classe, i record di output del mappatore vengono memorizzati direttamente nella tabella di output senza ordinarli e le fasi di ridistribuzione e riduzione del partizionamento vengono saltate).