segunda-feira, 19 de janeiro de 2015

BigData com Python e mrjob

Olá pessoal, nesse post nós iremos falar um pouquinho sobre BigData com Python. Iremos utilizar a biblioteca mrjob que é uma library que implementa MapReduce. A escolha do mrjob será justificada ao longo desse post.

BigData (como o próprio nome já denuncia) tem haver com grandes dados. BigData hoje é bastante utilizado para analisar os dados e tomar decisões dentro de uma empresa. Podemos citar como exemplo uma rede social que pode recomendar produtos aos seus usuários com base em análises de grandes volumes de dados.

Os desafios do BigData são trabalhar com grande volume de dados, velocidade para processar todos esses dados e variedade que são os dados provenientes de diversas fontes, qualidade etc.

Técnicas comuns de análise podem demorar bastante para serem processadas, o uso de BigData vem para melhorar isso, afinal você não gostaria de esperar dias, meses... para obter algum resultado proveniente de uma análise não é mesmo?

Temos também o conceito de escalabilidade, você pode alugar clusters (exemplo: Amazon) para processar esses dados. A computação em nuvem facilitou bastante tudo isso.

Algoritmos polinomiais podem ser paralelizados, ou seja, distribuir o processamento desse algoritmo.

Imagine uma tarefa grande que você deve realizar (exemplo: contar a quantidade de vezes que uma subsequência de DNA aparece numa sequência muito grande). Essa tarefa é distribuída em várias máquinas (cada máquina irá pegar uma parte da tarefa). Tem-se uma função (f) que é aplicada em cada partição para obtermos um conjunto de dados distribuídos.

MapReduce é um modelo de programação para processar grandes volumes de dados em paralelo. Quem já fez programas funcionais verá algo bem familiar.

O paradigma MapReduce possui entradas e saídas que geralmente são pares chaves/valores (dicionários).

Vamos ver um exemplo bem simples para entendermos melhor. A tarefa é contar a quantidade de vezes (frequência) que uma palavra aparece em um texto.

Segue um pseudo-código de MapReduce:


Perceba que temos duas operações: map e reduce. Na linha 2 temos "para cada palavra do texto", mapeia (linha 3) a palavra com frequência 1. A chave é a palavra.

Já o reduce (linha 5) pega uma chave de saída e um conjunto intermediário de valores (todas as frequências de uma determinada palavra nos mapeamentos). Depois basta percorrer a lista (linha 7) e fazer a soma. O resultado é a frequência de uma determinada palavra (chave).

Agora vamos falar sobre o mrjob que é uma biblioteca totalmente feita em Python que implementa o MapReduce.

Página do projeto: https://github.com/Yelp/mrjob

A instalação é muito simples, você pode instalar via pip (gerenciador de pacotes do Python). A partir da versão 2.7.9, o pip já vem por padrão. Caso você tenha uma versão do Python mais antiga, então precisará instalar o pip caso queira instalar a biblioteca através dele. Instalar o pip é muito fácil, clique aqui para ver um tutorial.

Para instalar via pip, basta dar o comando:

pip install mrjob

Caso você não queira instalar via pip, você pode baixar o código fonte do projeto e dar o seguinte comando (tem que está dentro do diretório onde se encontra o "setup.py" da biblioteca):

python setup.py install

Muito fácil não é mesmo? A instalação não oferece problemas (Python facilita muito as coisas heheh).

Eu irei utilizar o Python 2.7.6, não se preocupe se você possui uma outra versão, pois o mrjob é compatível com Python 2.5 ou superior.

Ah, justificando o porquê de utilizar o mrjob: é feito inteiramente em Python, é totalmente compatível com o serviço Amazon's Elastic MapReduce (EMR) e é muito simples de utilizar.

Nós vamos testar localmente, ou seja, não precisa ter a infraestrutura da Amazon.

Vamos fazer uma espécie de "Hello World" com MapReduce. Trata-se de um exemplo clássico que é contar a quantidade de vezes (frequência) das palavras em um texto.


Linha 5: importação do MRJob.

Linha 6: importação do módulo "re" que trata expressões regulares (regex).

Linha 8: essa linha utiliza o módulo de expressão regular "re". A função "compile" compila um padrão de expressão regular em um objeto de expressão regular que pode ser usado para casamento usando os métodos "match" e "search". A função "compile" recebe um padrão (pattern) que nesse caso é "[\w]+" que diz para pegar uma ou mais palavras (o "w" vem de "word"). Se você não estiver familiarizado com expressões regulares em Python, então clique aqui.

Linha 11: a classe MRWordFreqCount herda as funcionalidades da classe MRJob. Com isso basta sobrescrever os métodos mapper (linha 13) e reducer (linha 17). Há outros métodos que você pode sobrescrever, à medida que você for estudando o projeto irá conhecê-los.

O método mapper (linha 13) pega a chave e os valores (nesse caso a chave foi ignorada, daí o "_") como argumentos. A linha do texto é o valor.

Linha 14: o método "findall" procura por todas as ocorrências casadas em cada linha do texto.

Linha 15: utiliza-se o "yield" que é como se fosse um "return", mas a diferença é que ele retorna um generator. Oras, mas o que é um generator? Generators são iterables. Oras, mas o que são iterables? Um objeto é iterable quando você pode percorrer seus valores. Lembra das listas de compreensão? Então, essa é uma forma de criar iterables. Generators são iterables com a diferença que seus valores são lidos apenas quando é necessário. Complicou? Relaxe, você é humano :)

Veja só execução do yield utilizando o IDLE:


Quando a função é executada pela primeira vez, ela roda do começo e para até tocar no primeiro yield. Depois de tocar no primeiro yield, então ela continua de onde parou até achar o próximo yield. Quando não tiver um próximo yield então é lançada a exceção StopIteration. Agora melhorou né? :)

Dê uma olhada no algoritmo de contagem de palavras, lá é passada a palavra e a frequência 1. É o mesmo que acontece com o yield do exemplo com mrjob, é feito yield para cada palavra da linha.

Linha 17: é feito o reducer, ou seja, agrupamento de palavras com suas frequências (counts). É emitido (linha 18) uma palavra com o somatório das ocorrências (por isso é usada a função "sum"). Essas ocorrências é uma lista de 1's, basta somar para verificar quantas vezes uma determinada palavra aparece no texto.

Linha 22: chamada do método "run" para executar o MapReduce em cima das tarefas (mapper e reducer) que você definiu.

Vamos testar com algum arquivo pequeno, veja:


Para executar basta dar o seguinte comando:

python mr_word_freq_count.py arquivo.txt

Se quiser redirecionar a saída para outro arquivo faça:

python mr_word_freq_count.py arquivo.txt > saida.txt

Veja o resultado da saída:


Isso foi para um exemplo bem pequeno, mas imagine um texto grande como é o texto da posse do Obama. Clique aqui para fazer o download.

Vamos utilizar o texto da posse do Obama para verificar quantos caracteres, palavras e linhas ele possui. Veja o código:


Para executar, irei dar o comando:

python teste.py obama.txt > saida.txt

Conteúdo do arquivo "saida.txt":


Quaisquer dúvidas deixem nos comentários, até a próxima!


Nenhum comentário: