A redução de mapa é uma estrutura desenvolvida para processar grandes quantidades de dados com eficiência. Por exemplo, se tivermos 1 milhão de registros em um conjunto de dados e ele for armazenado em uma representação relacional - é muito caro derivar valores e realizar qualquer tipo de transformação neles.
Por exemplo, no SQL, Dada a data de nascimento, para descobrir quantas pessoas têm mais de 30 anos para um milhão de registros, isso levaria um tempo e isso só aumentaria em ordem de aumento quando a complexidade da consulta aumentar. O Map Reduce fornece uma implementação baseada em cluster, na qual os dados são processados de maneira distribuída
Outro bom exemplo é Encontrar amigos via redução de mapa pode ser um exemplo poderoso para entender o conceito e um caso de uso bem usado.
Encontrando Amigos
O MapReduce é uma estrutura desenvolvida originalmente no Google que permite fácil computação distribuída em larga escala em vários domínios. O Apache Hadoop é uma implementação de código aberto.
Vou abordar os detalhes, mas tudo se resume à definição de duas funções: uma função de mapa e uma função de redução. A função de mapa pega um valor e gera a chave: pares de valores. Por exemplo, se definirmos uma função de mapa que pega uma string e gera o comprimento da palavra como chave e a própria palavra como valor, o mapa (steve) retornaria 5: steve e map (savannah) retornaria 8: savannah . Você deve ter notado que a função map é sem estado e requer apenas o valor de entrada para calcular seu valor de saída. Isso nos permite executar a função map contra valores em paralelo e fornece uma enorme vantagem. Antes de chegarmos à função de redução, a estrutura mapreduce agrupa todos os valores por chave, portanto, se as funções de mapa produzirem a seguinte chave: pares de valores:
3 : the
3 : and
3 : you
4 : then
4 : what
4 : when
5 : steve
5 : where
8 : savannah
8 : research
Eles são agrupados como:
3 : [the, and, you]
4 : [then, what, when]
5 : [steve, where]
8 : [savannah, research]
Cada uma dessas linhas seria passada como argumento para a função de redução, que aceita uma chave e uma lista de valores. Nesse caso, podemos estar tentando descobrir quantas palavras de determinados comprimentos existem; portanto, nossa função de redução apenas conta o número de itens na lista e gera a chave com o tamanho da lista, como:
3 : 3
4 : 3
5 : 2
8 : 2
As reduções também podem ser feitas em paralelo, proporcionando novamente uma enorme vantagem. Podemos então olhar para esses resultados finais e ver que havia apenas duas palavras de comprimento 5 em nosso corpus, etc.
O exemplo mais comum de mapreduce é contar o número de vezes que as palavras ocorrem em um corpus. Suponha que você tenha uma cópia da Internet (tive a sorte de ter trabalhado em tal situação) e desejou uma lista de todas as palavras da Internet e quantas vezes isso ocorreu.
A maneira como você abordaria isso seria tokenizar os documentos que você possui (dividi-lo em palavras) e passar cada palavra para um mapeador. O mapeador cuspiria a palavra de volta juntamente com um valor de1
. A fase de agrupamento pegará todas as chaves (neste caso, palavras) e fará uma lista de 1s. A fase de redução pega uma chave (a palavra) e uma lista (uma lista de 1s para cada vez que a chave apareceu na internet) e resume a lista. O redutor então envia a palavra, juntamente com sua contagem. Quando tudo estiver dito e feito, você terá uma lista de todas as palavras na internet, além de quantas vezes ela apareceu.
Fácil né? Se você já leu sobre mapreduce, o cenário acima não é novidade ... é o "Olá, mundo" da mapreduce. Então, aqui está um caso de uso do mundo real (o Facebook pode ou não fazer o seguinte, é apenas um exemplo):
O Facebook tem uma lista de amigos (observe que os amigos são bidirecionais no Facebook. Se eu sou seu amigo, você é meu). Eles também têm muito espaço em disco e atendem a centenas de milhões de solicitações todos os dias. Eles decidiram pré-calcular os cálculos quando possível para reduzir o tempo de processamento de solicitações. Uma solicitação de processamento comum é o recurso "Você e Joe têm 230 amigos em comum". Quando você visita o perfil de alguém, vê uma lista de amigos que você tem em comum. Essa lista não muda frequentemente, portanto, seria um desperdício recalculá-la toda vez que você visitasse o perfil (com certeza você poderia usar uma estratégia de cache decente, mas não seria capaz de continuar escrevendo sobre mapreduce para esse problema). Vamos usar o mapreduce para que possamos calcular todos ' s amigos comuns uma vez por dia e armazene esses resultados. Mais tarde, é apenas uma pesquisa rápida. Temos muito disco, é barato.
Suponha que os amigos estejam armazenados como Pessoa -> [Lista de Amigos], nossa lista de amigos é então:
A -> B C D
B -> A C D E
C -> A B D E
D -> A B C E
E -> B C D
Cada linha será um argumento para um mapeador. Para cada amigo na lista de amigos, o mapeador produzirá um par de valores-chave. A chave será um amigo junto com a pessoa. O valor será a lista de amigos. A chave será classificada para que os amigos estejam em ordem, fazendo com que todos os pares de amigos sigam para o mesmo redutor. Isso é difícil de explicar com o texto, então vamos fazê-lo e ver se você pode ver o padrão. Após a execução de todos os mapeadores, você terá uma 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 linha será passada como argumento para um redutor. A função de redução simplesmente cruza as listas de valores e gera a mesma chave com o resultado da interseção. Por exemplo, reduzir ((AB) -> (ACDE) (BCD)) produzirá (AB): (CD) e significa que os amigos A e B têm C e D como amigos comuns.
O resultado após a redução é:
(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)
Agora, quando D visita o perfil de B, podemos rapidamente olhar para cima (B D)
e ver que eles têm três amigos em comum (A C E)
.