La riduzione delle mappe è un framework sviluppato per elaborare in modo efficiente enormi quantità di dati. Ad esempio, se abbiamo 1 milione di record in un set di dati ed è archiviato in una rappresentazione relazionale, è molto costoso ricavare valori ed eseguire qualsiasi tipo di trasformazione su di essi.
Ad esempio, in SQL, data la data di nascita, scoprire quante persone hanno un'età> 30 per un milione di record richiederebbe un po 'di tempo, e questo aumenterebbe solo in ordine di grandezza quando aumenta la complessità della query. Map Reduce fornisce un'implementazione basata su cluster in cui i dati vengono elaborati in modo distribuito
Un altro buon esempio è Trovare amici tramite la riduzione della mappa può essere un potente esempio per comprendere il concetto e un caso d'uso ben utilizzato.
Alla ricerca di amici
MapReduce è un framework originariamente sviluppato da Google che consente un facile calcolo distribuito su larga scala in numerosi domini. Apache Hadoop è un'implementazione open source.
Esaminerò i dettagli, ma si tratta di definire due funzioni: una funzione di mappa e una funzione di riduzione. La funzione mappa accetta un valore e genera chiave: coppie di valori. Ad esempio, se definiamo una funzione della mappa che accetta una stringa e genera la lunghezza della parola come chiave e la parola stessa come valore, allora map (steve) restituisce 5: steve e map (savannah) restituiscono 8: savannah . Potresti aver notato che la funzione mappa è senza stato e richiede solo il valore di input per calcolare il valore di output. Questo ci consente di eseguire la funzione della mappa su valori in parallelo e offre un enorme vantaggio. Prima di arrivare alla funzione di riduzione, il framework mapreduce raggruppa tutti i valori per chiave, quindi se le funzioni della mappa producono la seguente chiave: coppie di valori:
3 : the
3 : and
3 : you
4 : then
4 : what
4 : when
5 : steve
5 : where
8 : savannah
8 : research
Vengono raggruppati come:
3 : [the, and, you]
4 : [then, what, when]
5 : [steve, where]
8 : [savannah, research]
Ognuna di queste righe verrebbe quindi passata come argomento alla funzione di riduzione, che accetta una chiave e un elenco di valori. In questo caso, potremmo provare a capire quante parole di determinate lunghezze esistono, quindi la nostra funzione di riduzione conterà semplicemente il numero di elementi nell'elenco e produrrà la chiave con le dimensioni dell'elenco, come:
3 : 3
4 : 3
5 : 2
8 : 2
Le riduzioni possono anche essere fatte in parallelo, fornendo di nuovo un enorme vantaggio. Possiamo quindi guardare questi risultati finali e vedere che c'erano solo due parole di lunghezza 5 nel nostro corpus, ecc ...
L'esempio più comune di mapreduce è per contare il numero di volte in cui le parole si verificano in un corpus. Supponiamo che tu abbia una copia di Internet (sono stato abbastanza fortunato da aver lavorato in una situazione del genere) e che tu volessi un elenco di ogni parola su Internet e quante volte si è verificato.
Il modo in cui ti approcceresti sarebbe tokenizzare i documenti che hai (spezzarli in parole) e passare ogni parola a un mappatore. Il mappatore quindi sputerebbe indietro la parola con un valore di 1
. La fase di raggruppamento prenderà tutti i tasti (in questo caso parole) e farà un elenco di 1. La fase di riduzione prende quindi una chiave (la parola) e un elenco (un elenco di 1 per ogni volta che la chiave appare su Internet) e somma l'elenco. Il riduttore quindi emette la parola, insieme al conteggio. Quando tutto è detto e fatto avrai un elenco di ogni parola su Internet, insieme a quante volte è apparso.
Facile vero? Se hai mai letto su mapreduce, lo scenario sopra riportato non è una novità ... è il "Ciao, mondo" di mapreduce. Quindi, ecco un caso d'uso reale (Facebook può o non può effettivamente fare quanto segue, è solo un esempio):
Facebook ha un elenco di amici (nota che gli amici sono una cosa bidirezionale su Facebook. Se sono tuo amico, sei mio). Hanno anche molto spazio su disco e servono centinaia di milioni di richieste ogni giorno. Hanno deciso di pre-calcolare i calcoli quando possono ridurre i tempi di elaborazione delle richieste. Una richiesta di elaborazione comune è la funzione "Tu e Joe avete 230 amici in comune". Quando visiti il profilo di qualcuno, vedi un elenco di amici che hai in comune. Questo elenco non cambia frequentemente, quindi sarebbe inutile ricalcolarlo ogni volta che si visita il profilo (sicuro che si potrebbe utilizzare una strategia di cache decente, ma non sarei in grado di continuare a scrivere su mapreduce per questo problema). Utilizzeremo mapreduce in modo da poter calcolare tutti " s amici comuni una volta al giorno e memorizza questi risultati. Più tardi è solo una rapida ricerca. Abbiamo un sacco di dischi, è economico.
Supponiamo che gli amici siano memorizzati come Persona -> [Elenco di amici], quindi il nostro elenco di amici è:
A -> B C D
B -> A C D E
C -> A B D E
D -> A B C E
E -> B C D
Ogni riga sarà un argomento per un mapper. Per ogni amico nell'elenco di amici, il mapper produrrà una coppia chiave-valore. La chiave sarà un amico insieme alla persona. Il valore sarà l'elenco di amici. La chiave verrà ordinata in modo che gli amici siano in ordine, facendo sì che tutte le coppie di amici vadano allo stesso riduttore. Questo è difficile da spiegare con il testo, quindi facciamolo e vediamo se riesci a vedere lo schema. Dopo aver eseguito tutti i mapper, avrai un elenco come questo:
For map(A -> B C D) :
(A B) -> B C D
(A C) -> B C D
(A D) -> B C D
For map(B -> A C D E) : (Note that A comes before B in the key)
(A B) -> A C D E
(B C) -> A C D E
(B D) -> A C D E
(B E) -> A C D E
For map(C -> A B D E) :
(A C) -> A B D E
(B C) -> A B D E
(C D) -> A B D E
(C E) -> A B D E
For map(D -> A B C E) :
(A D) -> A B C E
(B D) -> A B C E
(C D) -> A B C E
(D E) -> A B C E
And finally for map(E -> B C D):
(B E) -> B C D
(C E) -> B C D
(D E) -> B C D
Before we send these key-value pairs to the reducers, we group them by their keys and get:
(A B) -> (A C D E) (B C D)
(A C) -> (A B D E) (B C D)
(A D) -> (A B C E) (B C D)
(B C) -> (A B D E) (A C D E)
(B D) -> (A B C E) (A C D E)
(B E) -> (A C D E) (B C D)
(C D) -> (A B C E) (A B D E)
(C E) -> (A B D E) (B C D)
(D E) -> (A B C E) (B C D)
Ogni riga verrà passata come argomento a un riduttore. La funzione di riduzione interseca semplicemente gli elenchi di valori e genera la stessa chiave con il risultato dell'intersezione. Ad esempio, ridurre ((AB) -> (ACDE) (BCD)) produrrà (AB): (CD) e significa che gli amici A e B hanno C e D come amici comuni.
Il risultato dopo la riduzione è:
(A B) -> (C D)
(A C) -> (B D)
(A D) -> (B C)
(B C) -> (A D E)
(B D) -> (A C E)
(B E) -> (C D)
(C D) -> (A B E)
(C E) -> (B D)
(D E) -> (B C)
Ora quando D visita il profilo di B, possiamo rapidamente cercare (B D)
e vedere che hanno tre amici in comune (A C E)
.