Map reduce es un marco desarrollado para procesar cantidades masivas de datos de manera eficiente. Por ejemplo, si tenemos 1 millón de registros en un conjunto de datos, y está almacenado en una representación relacional, es muy costoso derivar valores y realizar cualquier tipo de transformación en estos.
Por ejemplo, en SQL, dada la fecha de nacimiento, averiguar cuántas personas tienen> 30 años por un millón de registros llevaría un tiempo, y esto solo aumentaría en orden de aumento cuando aumente la complejidad de la consulta. Map Reduce proporciona una implementación basada en clúster donde los datos se procesan de manera distribuida
Otro buen ejemplo es Finding Friends via map reduce puede ser un ejemplo poderoso para entender el concepto y un caso de uso bien utilizado.
Encontrar amigos
MapReduce es un marco desarrollado originalmente en Google que permite una computación distribuida fácil a gran escala en varios dominios. Apache Hadoop es una implementación de código abierto.
Voy a pasar por alto los detalles, pero se trata de definir dos funciones: una función de mapa y una función de reducción. La función de mapa toma un valor y genera la clave: pares de valores. Por ejemplo, si definimos una función de mapa que toma una cadena y genera la longitud de la palabra como la clave y la palabra misma como el valor, map (steve) devolvería 5: steve y map (savannah) devolvería 8: savannah . Es posible que haya notado que la función de mapa no tiene estado y solo requiere el valor de entrada para calcular su valor de salida. Esto nos permite ejecutar la función de mapa contra valores en paralelo y proporciona una gran ventaja. Antes de llegar a la función de reducción, el marco mapreduce agrupa todos los valores por clave, por lo que si las funciones de mapa generan la siguiente clave: pares de valores:
3 : the
3 : and
3 : you
4 : then
4 : what
4 : when
5 : steve
5 : where
8 : savannah
8 : research
Se agrupan como:
3 : [the, and, you]
4 : [then, what, when]
5 : [steve, where]
8 : [savannah, research]
Cada una de estas líneas se pasaría como un argumento a la función reducir, que acepta una clave y una lista de valores. En este caso, podríamos estar tratando de averiguar cuántas palabras existen de ciertas longitudes, por lo que nuestra función de reducción solo contará el número de elementos en la lista y generará la clave con el tamaño de la lista, como:
3 : 3
4 : 3
5 : 2
8 : 2
Las reducciones también se pueden hacer en paralelo, lo que nuevamente ofrece una gran ventaja. Luego podemos ver estos resultados finales y ver que solo había dos palabras de longitud 5 en nuestro corpus, etc.
El ejemplo más común de mapreduce es contar el número de veces que las palabras aparecen en un corpus. Suponga que tiene una copia de Internet (he tenido la suerte de haber trabajado en una situación así) y quería una lista de todas las palabras en Internet, así como cuántas veces ocurrió.
La forma en que abordaría esto sería tokenizar los documentos que tiene (dividirlos en palabras) y pasar cada palabra a un mapeador. El mapeador entonces escupiría la palabra junto con un valor de 1
. La fase de agrupación tomará todas las claves (en este caso, palabras) y hará una lista de 1. La fase de reducción toma una clave (la palabra) y una lista (una lista de 1 por cada vez que aparece la clave en Internet), y suma la lista. El reductor luego genera la palabra, junto con su recuento. Cuando todo esté dicho y hecho, tendrá una lista de cada palabra en Internet, junto con cuántas veces apareció.
Fácil, verdad? Si alguna vez has leído sobre mapreduce, el escenario anterior no es nada nuevo ... es el "Hola, Mundo" de mapreduce. Así que aquí hay un caso de uso del mundo real (Facebook puede o no hacer lo siguiente, es solo un ejemplo):
Facebook tiene una lista de amigos (tenga en cuenta que los amigos son algo bidireccional en Facebook. Si soy su amigo, usted es mío). También tienen mucho espacio en disco y atienden cientos de millones de solicitudes todos los días. Han decidido calcular previamente los cálculos cuando pueden para reducir el tiempo de procesamiento de las solicitudes. Una solicitud de procesamiento común es la función "Usted y Joe tienen 230 amigos en común". Cuando visitas el perfil de alguien, ves una lista de amigos que tienes en común. Esta lista no cambia con frecuencia, por lo que sería un desperdicio volver a calcularla cada vez que visitara el perfil (seguro de que podría usar una estrategia de almacenamiento en caché decente, pero entonces no podría seguir escribiendo sobre mapreduce para este problema). Vamos a utilizar mapreduce para poder calcular a todos ' s amigos comunes una vez al día y almacenar esos resultados. Más tarde es solo una búsqueda rápida. Tenemos muchos discos, es barato.
Supongamos que los amigos se almacenan como Persona -> [Lista de amigos], nuestra lista de amigos es entonces:
A -> B C D
B -> A C D E
C -> A B D E
D -> A B C E
E -> B C D
Cada línea será un argumento para un mapeador. Para cada amigo en la lista de amigos, el asignador generará un par clave-valor. La clave será un amigo junto con la persona. El valor será la lista de amigos. La clave se ordenará para que los amigos estén en orden, haciendo que todos los pares de amigos vayan al mismo reductor. Esto es difícil de explicar con texto, así que hagámoslo y veamos si puedes ver el patrón. Después de que todos los mapeadores hayan terminado de ejecutarse, tendrá una lista como esta:
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)
Cada línea se pasará como argumento a un reductor. La función reducir simplemente intersecará las listas de valores y generará la misma clave con el resultado de la intersección. Por ejemplo, reducir ((AB) -> (ACDE) (BCD)) generará (AB): (CD) y significa que los amigos A y B tienen C y D como amigos comunes.
El resultado después de la reducción es:
(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)
Ahora, cuando D visita el perfil de B, podemos buscar rápidamente (B D)
y ver que tienen tres amigos en común (A C E)
,.