Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Job MapReduce: un esempio in Java

Analizziamo un esempio riguardante la progettazione e l'implementazione di un job MapReduce il cui compito sarà quello di calcolare le occorrenze (cioè il numero di ripetizioni) dei termini presenti nel testo di un file.
Analizziamo un esempio riguardante la progettazione e l'implementazione di un job MapReduce il cui compito sarà quello di calcolare le occorrenze (cioè il numero di ripetizioni) dei termini presenti nel testo di un file.
Link copiato negli appunti

In questo capitolo verrà proposto un esempio molto semplice e nello stesso tempo molto comune per i contesti di elaborazione distribuita: il word counting. Verrà infatti, progettato e implementato un job MapReduce che calcolerà le occorrenze dei termini presenti nel testo di un file.

Progettazione del job MapReduce

Per la progettazione del dovremo predisporre una funzione di tipo map che legga il contenuto di un file e lo inoltri ad una (o più) funzione reduce che provvederà a contare le occorrenze. Di seguito lo schema funzionale di ciò che andremo ad implementare.

Figura 1. Schema funzionale del job da realizzare
Schema funzionale del job da realizzare

Se conoscessimo bene il framework di Hadoop, potremmo anche pensare di progettare quali siano gli input e gli output delle funzioni map e reduce sulla base dell'elaborazione da svolgere. Ad esempio: siamo sicuri che i valori di input della funzione map sono le righe di testo del file di input pertanto possiamo pensare di utilizzare un oggetto di tipo Text (presente nel framework) per incapsulare il testo letto e utilizzarlo come ValueIN.

Per quanto riguarda la KeyIN, la funzione map() riceverebbe un oggetto che rappresenta la chiave associata al valore rappresentato dall'oggetto Text. Una delle possibilità è quella di scegliere come chiave un valore numerico, (solo questa volta) suggeriamo di scegliere un oggetto di tipo LongWritable (appartenente anch'esso al framework).

Per quanto riguarda gli output invece, immaginando di voler ottenere come risultato un elenco di termini in cui ogni parola è affiancata dal valore che ne rappresenta le occorrenze, possiamo pensare che la singola parola sia la KeyOUT e che il ValueOUT sia rappresentato dal valore dell'occorrenza. Sulla base di questa considerazione possiamo pensare che la chiave di output sia un oggetto di tipo Text che incapsula una parola letta e che il valore di output sia un oggetto di tipo IntWritable che incapsula un valore iniziale del conteggio dell'occorrenza per la parola corrente (ricordiamo infatti che è un output intermedio e non finale della funzione reduce). Il dettaglio della progettazione della funzione Map risulterebbe quindi quello della figura sottostante:

Figura 2. Dettaglio funzionale della funzione Map
Dettaglio funzionale della funzione Map

Con analoghe considerazioni e con la conoscenza dei tipi degli oggetti di output della funzione map, possiamo pensare di progettare gli input e gli output della funzione reduce. Gli output di map, diventano gli input della funzione reduce, quindi dovremmo predisporre oggetti dello stesso tipo. A differenza della funzione map però, in reduce possiamo trovare un elenco di valori di input associati ad una KeyIN.

Il framework permette la gestione di questo dettaglio utilizzando l'oggetto Iterable<valuein> parametrizzato con il tipo di oggetto che abbiamo scelto e che incapsula l'elenco dei valori associati alla KeyIN. Tenendo sempre in considerazione quello che è l'output finale, possiamo pensare che anche gli oggetti di output della funzione reduce siano dello stesso tipo degli oggetti di input. Quindi il dettaglio della progettazione della funzione reduce risulterebbe come in figura:

Figura 3. Dettaglio funzionale della funzione Reduce
Dettaglio funzionale della funzione Reduce

e il dettaglio funzionale dell'intero job MapReduce risulta essere il seguente:

Figura 4. Dettaglio funzionale della funzione Reduce
Dettaglio funzionale della funzione Reduce

Sviluppo del job MapReduce

Per lo sviluppo del codice è stato utilizzato Eclipse Java EE Juno. Per gestire un progetto di questo tipo, utilizzeremo inoltre il tool Maven. Dopo aver creato il progetto in Eclipse, ci troveremo di fronte ad un risultato simile a quello in figura:

Figura 5. Il progetto di esempio in Eclipse
Il progetto di esempio in Eclipse

Grazie all’utilizzo di Maven, possiamo aggiungere la dipendenza di Hadoop configurando il file pom.xml; in particolare, ci assicureremo di impostare repository e dipendenza come segue:

<dependencies>
	<dependency>
		<groupId>org.apache.hadoop</groupId>
		<artifactId>hadoop-core</artifactId>
		<version>0.20.2</version>
	</dependency>
</dependencies>

Una volta configurato pom.xml, possiamo utilizzare il framework. Prima di tutto, creiamo 3 diversi package in src/main/java:

Package Descrizione
html.it.hadoop.wordcount.map Conterrà le classi che implementano le funzioni Map
html.it.hadoop.wordcount.reduce Conterrà le classi che implementano le funzioni Reduce
html.it.hadoop.wordcount Conterrà la classe che implementa il Main dell'applicazione

L’albero progetto risultante dalla creazione dei 3 package descritti sarà il seguente:

Figura 6. Albero progetto dei package
Albero progetto dei package

Completato lo sviluppo del job MapReduce, nel prossimo capitolo si passerà alla procedura necessaria per l'implementazione della Map.


Ti consigliamo anche