Risposte:
Fondamentalmente sono problemi enormi, ma non difficili. Il commesso viaggiatore dipende fondamentalmente dalla distanza tra una data coppia di città, quindi mentre può essere suddiviso in molte parti, i risultati parziali non possono essere ricombinati in modo che emerga la soluzione globalmente ottimale (beh, probabilmente no; se conosci un modo, richiedi subito la tua medaglia Fields).
D'altro canto, contare le frequenze delle parole in un gigantesco corpus è banalmente partizionabile e banalmente ricombinabile (basta sommare i vettori calcolati per i segmenti del corpus), quindi la riduzione della mappa è la soluzione ovvia.
In pratica, più problemi tendono ad essere facilmente ricombinabili che no, quindi la decisione se parallelizzare un compito o meno ha più a che fare con l'entità del compito, e meno con quanto sia difficile.
Il problema può essere risolto in modo efficiente utilizzando il calcolo distribuito?
Se la risposta a questa domanda è sì, allora hai un problema candidato per MapReduce. Questo perché il modello del problema si presta ad essere suddiviso in piccoli problemi isolati.
Il tuo compito: analizzare questo libro
Un esempio funziona bene per illustrare questo. Hai un documento di grandi dimensioni ( Moby Dick di Herman Melville ) e il tuo compito è quello di eseguire un'analisi di frequenza di tutte le parole utilizzate in esso.
L'approccio sequenziale
Puoi farlo in sequenza ottenendo la tua macchina più veloce (ne hai molte in giro) e scorrendo il testo dall'inizio alla fine mantenendo una mappa hash di ogni parola che trovi (la chiave) e incrementando la frequenza (valore) ogni volta analizzi una parola. Semplice, diretto e lento.
L'approccio MapReduce
Accedendo a questo da una prospettiva diversa, noti che hai tutte queste macchine di riserva in giro e potresti dividere questo compito in pezzi. Assegna a ogni macchina un blocco di testo da 1 Mb per analizzare in una mappa hash e quindi raccogliere tutte le mappe hash da ciascuna in un unico risultato. Questa è una soluzione MapReduce a più livelli.
Il processo di lettura di una riga di testo e raccolta delle parole è la fase Mappa (si crea una semplice mappa che rappresenta le parole nella linea con la loro frequenza 1,2,3 ecc.), Quindi la fase Riduzione è quando ogni macchina raccoglie la loro linea mappe in un'unica mappa aggregata.
La soluzione complessiva deriva da un'ulteriore fase di Riduzione in cui tutte le mappe aggregate vengono aggregate (quella parola di nuovo) in una mappa finale. Leggermente più complesso, enormemente parallelo e rapido.
Sommario
Quindi, per riassumere, se il tuo problema si presta ad essere rappresentato da chiavi, valori, operazioni aggregate su quei valori in isolamento, allora hai un problema candidato per MapReduce.
Il modello MapReduce è tratto dal mondo della programmazione funzionale. È un processo per applicare qualcosa chiamato catamorfismo su una struttura di dati in parallelo. I programmatori funzionali usano i catamorfismi praticamente per ogni semplice trasformazione o sintesi.
Supponendo che i tuoi dati siano un albero, il fattore decisivo è se puoi calcolare un valore per un nodo usando solo i dati contenuti in quel nodo e i valori calcolati per i suoi figli.
Ad esempio puoi calcolare la dimensione di un albero usando un catamorfismo; calcoleresti la somma dei valori calcolati per tutti i bambini più uno.
Questo WPI - Applicazioni di Map Reduce (ppt) potrebbe interessarti. Discute diverse applicazioni di MR e, come uno dei casi discussi, mostra come Utilizzando 100 istanze EC2 e 24 ore, il New York Times è stato in grado di convertire 4 TB di articoli digitalizzati in 1,5 TB di documenti PDF.
Un'altra serie di esempi in cui MR ha aiutato a velocizzare le prestazioni è la seguente: Aster - SQL Map Reduce mostra alcuni casi di studio della tecnologia SQL-Map Reduce tra cui il rilevamento delle frodi, le trasformazioni e altri.
Mappa / Riduci è una forma specifica di un tipo specifico di algoritmo. Lo usi per trasformare un enorme set di dati in un altro set di dati. (Il set di dati dei risultati può essere o meno enorme). Se non si desidera impostare un output di dati statici come risultato dell'input di dati statici, Map / Reduce non è appropriato. Map / Reduce può facilmente dirti quanti John Smith sono presenti nella rubrica di Manhattan, ma non è adatto per costruire un server web.
Il modo in cui funziona Map / Reduce è:
Il risultato è che un elenco di coppie (k1, v1) viene trasformato in un elenco di (v3) s. (Naturalmente, il valore "v3" può essere un composito che include k2, che può essere definito uguale a k1.)
Quindi lo usi:
Se hai così tanti dati per iniziare con quello eseguirli tutti in sequenza attraverso uno o due server, richiederebbe troppo tempo, e
Puoi concepire i dati di output come un elenco di valori o coppie di valori chiave (generalmente non troppo difficile quando ricordi che "chiave" significa solo "etichetta univoca"), e
Qualunque sia la relazione, si è certi che ciascun dato di input influisce solo sul valore di output per una chiave di output.
Se tutti i tuoi dati possono essere elaborati in sequenza da un singolo server, dal momento che questo è il paradigma informatico dominante (quelli per cui sono stati creati i server e su cui sono programmati i programmatori), usa un singolo server.
Lo stage della mappa deve suddividere tutti i dati di input in base alla chiave di output. Non deve produrre il valore di output associato alla chiave di output (fatto dallo stage di riduzione), ma deve assegnare in modo univoco ciascuna coppia di valori della chiave di input per contribuire al massimo al valore di una chiave di output. Se i dati sono troppo correlati, la riduzione della mappa potrebbe non essere in grado di gestire il problema. D'altra parte, potrebbe essere solo necessario utilizzare più round di mappa / riduzione.
Se non riesci a capire come trasformare la trasformazione dei tuoi dati in una mappa / riduzione, ovviamente non è una soluzione.
C'è una vera arte per capire se un problema può essere scomposto in qualcosa che Map / Reduce può gestire. Ad esempio, v1 e v2 potrebbero non essere presenti nei set di dati di input o output. Se vuoi solo contare elementi univoci nei dati di input, allora k1 = k2 = un oggetto e v1 = v2 = 1 o 0 o davvero qualsiasi cosa. Reduce produce solo v3 come la somma del numero di k2 che è stato dato.
Quindi è difficile affermare con certezza che non è possibile eseguire una trasformazione dei dati utilizzando Mappa / Riduci, ma quanto sopra fornisce alcune indicazioni.
MapReduce funziona su qualsiasi problema costituito da esattamente 2 funzioni a un certo livello di astrazione. La prima funzione viene applicata a ciascuno degli elementi nel set di input e la seconda funzione aggrega i risultati.
Pertanto, ogni volta che si desidera ottenere (1) risultati da (n) input e tutti gli input possono essere esaminati / utilizzati dalla funzione (1), è possibile utilizzare MapReduce. Ancora una volta, questo è ad un livello specifico di astrazione. La funzione (1) può essere una funzione di raggruppamento che controlla l'ingresso e decide quale di altre altre funzioni utilizzare.
Ciò è utile quando non si conosce in anticipo la quantità di input che si avrà, quando è necessario condividere "unità" discrete di lavoro o quando si desidera che un singolo ritorno rappresenti l'intero risultato (IE esegue cinquemila test di unità e se meno di x% fallisce, restituisce successo).
La maggior parte delle risposte qui sembrano essere una variante della spiegazione di cosa riduce la mappa, il che è valido. Ma per rispondere alla domanda, quale era quale modello segnalerebbe dove potresti essere in grado di utilizzare la riduzione della mappa non è realmente affrontato da questo.
Se l'implementazione ingenua, non funzionale, del problema che stai esaminando comporta il looping su qualcosa e quindi l'aggiornamento di qualcosa al di fuori del loop con un certo stato all'interno del loop, è probabile che tu abbia qualcosa che le porte riducano bene la mappa. Soprattutto se è possibile generalizzare l'aggiornamento dello stato centrale a una funzione che funziona con solo due parametri e può garantire che questa funzione sia commutativa e associativa.
Il motivo per cui potresti voler utilizzare la riduzione della mappa se ciò è vero è duplice: 1) potrebbe essere un po 'più pulito e più semplice testare ed eseguire il debug se dividi le cose nella mappa e riduci le funzioni. 2) le funzioni di riduzione della mappa sono senza stato e possono essere eseguite contemporaneamente, il che accelera le cose se hai più cpus disponibili e qualcosa come hadoop o spark che ne fa uso per eseguire le cose in un cluster.
Questo è utile se esegui il loop su molte cose, ma il tuo chilometraggio può variare a seconda della complessità della mappa / riduzione. È abbastanza comune finire con una catena sequenziale o un albero di riduzioni delle mappe in cui alla fine tutto è ancora strozzato in una complessa fase di riduzione alla fine della catena. Ad esempio, molti algoritmi grafici sono difficili da scalare in modo efficiente con la sola riduzione della mappa.
L'esempio più semplice che funziona bene con la riduzione delle mappe è il conteggio delle cose, che è una riduzione molto economica. Questo è il motivo per cui il conteggio delle parole è un esempio spesso usato per ridurre la mappa. Puoi praticamente aspettarti una scalabilità lineare per le prestazioni con quel caso d'uso: ogni CPU che aggiungi rende più veloce.
Se fai molta programmazione funzionale, inizi a imbatterti in situazioni che richiedono una mappa generale e riducono. Probabilmente li vedi anche nella programmazione imperativa, ma non li riconosci dietro la maschera di anelli e accumulatori.
Come esempio di quello che mi è venuto in mente di recente, ho lavorato su un parser di Haskell. Per testare il mio parser, pompa un elenco di frammenti di stringa attraverso il parser, quindi desidero ottenere una singola stringa in modo da poter generare i miei risultati per vedere se è stata analizzata correttamente. Quindi sembra che:
--my initial set of test data, a list
tests = ["string1", "string2", "string3", ...]
--Map Step: turn strings into parsed results
--note the type, which demonstrates the map
applyParser :: [String] -> [Token]
--The actual function
applyParser input = map parser input
--Second map, turn tokens into output
showTokens :: [Token] -> [String]
showTokens t = map show t
--Reduce step, concat the results
combineResults :: [String] -> String
--In haskell, reduce is the foldl function, which takes an operation to fold with, a starting element, and a list to fold on
combineResults strings = foldl concat "" strings
--Finished program
testParser = print (combineResults(showTokens(applyParser tests)))
Certo, questo è solo pedagogico. Il mio codice attuale sembra un po 'diverso, e utilizza le funzioni più interne (come fold concat
non è necessario in quanto include già Haskell unlines
che fa [String]->String
). Il mio punto principale era che non avevo previsto di usare una mappa / riduzione quando ho iniziato, ma si è allineato alle mie esigenze. Volevo fare alcune cose con le liste, quindi trasformare la mia lista in un singolo elemento di output. L'uso della mappa / riduzione è emerso naturalmente.
L'elaborazione delle stringhe (come l'analisi) è un uso molto ovvio della riduzione della mappa, la mappatura è l'applicazione di varie trasformazioni sul testo di input e la riduce rimettendo insieme il testo del risultato come output. Allo stesso modo, un compilatore potrebbe essere simile, usando le pieghe per trasformare un flusso di elementi dell'albero di sintassi astratto in una forma migliore (ottimizzazione).
È parallelizzabile?
Qualsiasi problema parallelizzabile è essenzialmente mappa e piega; al contrario, il passaggio della mappa è intrinsecamente parallelizzabile (e il passaggio di piegatura potrebbe essere, a seconda della struttura su cui è piegato), quindi questa è una proprietà bidirezionale.
Supponiamo che tu stia cercando un cluster di server e che uno non sia in grado di rispondere in quel momento. Quello che farà mapReduce è che non è in grado di accedere a quel nodo dell'albero sulla mappa più grande è che lo riprogrammerà per dopo e quindi eseguirà la mappa o la riduzione. In sostanza cerca di garantire che tutte le informazioni siano disponibili con l'imprevedibilità di software e hardware negli ambienti.
Ecco le principali domande che utilizzo per sondare la decisione di utilizzare (o non utilizzare) MapReduce.
Il problema che sto cercando di risolvere si decompone in operazione Mappa e Riduci?
in effetti, è un modello generico di "divisione e conquista", in modo che le soluzioni per la distribuzione del calcolo possano essere scritte genericamente.
un semplice esempio è come un documento di grandi dimensioni. il problema è che vuoi contare il numero di lettere in quel documento. invece di essere eseguito su un singolo computer, è possibile suddividerlo in una matrice di tutte le parole nel documento. quindi puoi elaborare ogni parola singolarmente e i risultati insieme.
il modello è utile, perché una volta che si ottiene una mappa generica / si riduce l'implementazione funzionante, è possibile risolvere qualsiasi problema utilizzando lo stesso livello software, è sufficiente esprimere il problema in termini di esso.