18/10/2017 Larissa Bonifácio Roder

MapReduce e sua utilidade

Um dos grandes desafios computacionais da atualidade é a manipulação inteligente de grande quantidade de dados. Sistemas corporativos, serviços e sistemas Web, mídias sociais e entre outros, produzem um volume impressionante de dados.

A maioria desses dados são armazenados de forma não-estruturada, além de linguagens e formatos diversos, em muitos casos, incompatíveis entre si. Esses se tornaram uma valiosa fonte de informação. Um exemplo de manipulação de grande quantidade de dados é a empresa Google, que não possui um alto valor agregado somente por seu poderoso algoritmo de busca de páginas Web e seus inúmeros serviços disponíveis, mas também por manter um grande volume de dados de seus usuários.

São esses dados que, ao passarem por análises, tendem a se tornar valiosos, permitindo a criação de soluções inteligentes. Neste artigo será abordado o modelo MapReduce e sua utilização para a manipulação de grande quantidade de dados. Esse foi proposto primeiramente pela empresa citada no exemplo anterior: a Google, no ano de 2004.

O funcionamento do MapReduce

O MapReduce possui um conjunto de informações único, que é dividido em unidades e estas unidades são mapeadas paralelamente. Logo após, possuem-se as etapas de sort e shuffle: o sort ordena esses dados e o shuffle é a distribuição dos dados organizados em grupos para serem atribuídos aos nós de Redução.

Esse modelo demonstrou ser adequado para trabalhar com problemas que podem ser particionados ou fragmentados em subproblemas. As funções Map e Reduce podem ser aplicadas separadamente a um conjunto de dados. Se os dados forem suficientemente grandes, podem ainda ser divididos para serem executados em diversas funções Map ao mesmo tempo.

MapReduce processo de contagem de palavras

Figura 1

Para entendermos melhor vamos analisar a Figura 1 com um grupo de palavras a serem analisadas:

Input: Grupo de palavras informadas para análise;

Splitting: Divisão do grupo de palavras em pequenas unidades;

Mapping: Na fase de mapeamento é atribuído um peso aos objetos. No caso do exemplo foi atribuído peso igual a 1 para cada palavra das unidades;

Shuffling: Nessa fase são agrupados os valores escritos no map que possuem mesma chave, preparando para aplicar a redução;

Reduce: Essa fase fica responsável por verificar o número de repetições.no exemplo, o número de palavras repetidas;

Final Result: Quantidade de cada Palavra contida na lista de entrada.

Um exemplo de implementação utilizando MapReduce com Stream API em Java

public class CountWords {

 

public static void main(String[] args) throws IOException {

Path path = Paths.get(<Caminho do arquivo>);

Map<String, Integer> wordCount = Files.lines(path)

//input

.flatMap(line -> Arrays.stream(line.trim().split(” “)))

//spliting

.map(word -> word.replaceAll(“[^a-zA-Z]”, “”).toLowerCase().trim())

.filter(word -> word.length() > 0)

//mapping

.map(word -> new AbstractMap.SimpleEntry<>(word, 1))

//Sort and Shuffle

.sorted(Comparator.comparing(AbstractMap.SimpleEntry::getKey))

//Reduce

.reduce(new LinkedHashMap<>(), getTotalEachWord(), getLinkedHashMapBinaryOperator());

wordCount.forEach((k, v) -> System.out.println(String.format(“%s ==>> %d”, k, v)));

}

 

private static BinaryOperator<LinkedHashMap<String, Integer>> getLinkedHashMapBinaryOperator() {

return (m1, m2) -> m1;

}

 

private static BiFunction<LinkedHashMap<String, Integer>, AbstractMap.SimpleEntry<String, Integer>, LinkedHashMap<String, Integer>> getTotalEachWord() {

return (acc, entry) -> {

acc.put(entry.getKey(), getCompute(acc, entry));

return acc;

};

}

 

private static Integer getCompute(LinkedHashMap<String, Integer> acc, AbstractMap.SimpleEntry<String, Integer> entry) {

return acc.compute(entry.getKey(), (k, v) -> Objects.isNull(v) ? 1 : v + 1);

}

}

Vamos por partes:

.flatMap(line -> Arrays.stream(line.trim().split(” “))): Responsável por separar o grupo de palavras;

.map(word -> word.replaceAll(“[^a-zA-Z]”, “”).toLowerCase().trim())

.filter(word -> word.length() > 0): Responsável por dividir esse grupo de palavras em unidades;

.sorted(Comparator.comparing(AbstractMap.SimpleEntry::getKey)): Organiza em grupos de palavras idênticas;

.reduce(new LinkedHashMap<>(), getTotalEachWord(), getLinkedHashMapBinaryOperator()): Neste ponto utiliza o Recurso de interfaces funcional BiFunction e BinaryOperator para calcular a quantidade de palavras repetidas no texto.

Muitos dados, sem problemas.

O MapReduce tem sido usado com sucesso, possui fácil utilização mesmo para programadores sem experiência. Uma grande variedade de problemas são facilmente expressados com esta técnica.

Referências

http://www.ic.unicamp.br/~cortes/mo601/trabalho_mo601/tiago_cruz_map_reduce/relatorio.pdf

http://www.univale.com.br/unisite/mundo-j/artigos/53_Mapreduce.pdf

Vídeo Hadoop/MapReduce

Tagged: ,

Sobre o autor

Larissa Bonifácio Roder Larissa Roder é Desenvolvedora Java há quase três anos, Mestranda em Computação Aplicada pela UTFPR de Cornélio Procópio e possui certificação OCAJ7.