DevSecOps

21 mai, 2012

Utilize linguagens parecidas com a SQL para a estrutura do MapReduce

Publicidade

Nas últimas duas décadas, o aumento estável do poder computacional produziu um fluxo impressionante de dados que, por sua vez, causou uma mudança de paradigmas dos mecanismos de arquitetura de computação e de processamento de dados em grande escala. Por exemplo, os eficientes telescópios em astronomia, os aceleradores de partículas em física e os sequenciadores de genoma em biologia inserem volumes massivos de dados nas mãos dos cientistas. O Facebook coleta 15 TeraBytes de dados por dia em um data warehouse com escala de PetaBytes. A demanda por aplicativos de análise e mineração de dados em grande escala está crescendo nos segmentos de mercado (por exemplo, análise de dados da web, análise de fluxo de cliques e análise de logs de monitoramento de rede) e nas ciências (por exemplo, análise de dados produzidos por simulações de escala massiva, implementações de sensores e equipamentos laboratoriais de alta produção). Embora os sistemas de bancos de dados paralelos atendam a alguns desses aplicativos de análise de dados, eles são caros, difíceis de administrar e não têm tolerância a falhas para consultas de longa execução.

O MapReduce é uma estrutura apresentada pelo Google para programação de clusters de computadores de prateleira, a fim de executar o processamento de dados em grande escala em uma única execução. A estrutura é desenvolvida para que o cluster do MapReduce possa ser escalado a milhares de nós de modo tolerante a falhas. No entanto, o modelo de programação do MapReduce tem suas próprias limitações. Seu fluxo de dados de uma entrada e dois estágios é extremamente rígido, além do fato de ter um nível muito baixo. Por exemplo, é preciso gravar um código customizado até mesmo para operações mais comuns. Portanto, muitos programadores se sentem desconfortáveis com essa estrutura e preferem usar a SQL como uma linguagem declarativa de alto nível. Diversos projetos (Apache Pig, Apache Hive e HadoopDB) foram desenvolvidos para facilitar a tarefa dos programadores e fornecer interfaces declarativas de alto nível à estrutura do MapReduce.

Primeiro, analise a estrutura do MapReduce e, em seguida, os recursos dos diferentes sistemas que fornecem interfaces de alto nível a essa estrutura.

A estrutura do MapReduce

Uma principal vantagem da abordagem da estrutura do MapReduce é que ela isola o aplicativo dos detalhes da execução de um programa distribuído, como problemas de distribuição de dados, planejamento e tolerância a falhas. Nesse modelo, o cálculo toma um conjunto de pares de chaves/valores e produz um conjunto de pares de chaves/valores de saída. O usuário do MapReduce expressa o cálculo usando duas funções: Mapear e Reduzir. A função Mapear toma um par de entrada e produz um conjunto de pares de chaves/valores intermediários. A estrutura do MapReduce agrupa todos os valores intermediários associados à mesma chave intermediária Eu (shuffling) e os transfere à função Reduzir . A função reduzir recebe uma chave intermediária Eu com seu conjunto de valores e realiza sua fusão. Geralmente, somente o valor de saída zero ou um é produzido de acordo com a chamada reduzir . A principal vantagem desse modelo é que ele permite que grandes cálculos sejam feitos em paralelo e reexecutados como o principal mecanismo de tolerância a falhas.

O projeto Apache Hadoop é um software livre Java que oferece suporte a aplicativos distribuídos de dados intensos por meio da implementação da estrutura do MapReduce. Ele foi desenvolvido originalmente pelo Yahoo! como um clone da infraestrutura MapReduce do Google, mas, logo em seguida, tornou-se um software livre. O Hadoop é responsável pela execução de seu código em um cluster de máquinas. Em geral, quando um conjunto de dados ultrapassa a capacidade de armazenamento de uma única máquina física, é necessário particioná-lo em um número de máquinas separadas. Os sistemas de arquivos que gerenciam o armazenamento em uma rede de máquinas são chamados sistemas de arquivos distribuídos. O Hadoop vem com um sistema de arquivos distribuído chamado HDFS (Sistema de Arquivos Distribuído Hadoop). Em particular, o HDFS é um sistema de arquivos distribuído que armazena os arquivos entre todos os nós em um cluster Hadoop. Ele quebra os arquivos em grandes blocos e os distribui entre diferentes máquinas, além de fazer diversas cópias de cada bloco para que, se uma máquina falhar, nenhum dado seja perdido.

O programa do MapReduce na Lista 1 é expresso em um pseudocódigo para contagem do número de ocorrências de cada palavra em um sequência de linhas de texto. Na Lista 1, a funçãomapear emite cada palavra, mais uma marca associada de ocorrências, ao passo que a função reduzir soma todas as marcas emitidas para uma palavra em particular.

  map(chave da Sequência, valor da Sequência):
//key: número da linha, valor: texto da linha
para cada palavra w do valor:
EmitIntermediate(w, ?1?);

reduce(chave da Sequência, valores do Agente iterativo):
//key: uma palavra, valores: uma lista de contagens
int wordCount = 0;
para cada v dos valores:
wordCount += ParseInt(v);
Emit(AsString(wordCount));

Lista 1. Programa do MapReduce

Agora, suponha que a sequência de entrada das linhas do texto da Lista 2:

1, Este é o Código Exemplo
2, A Cor Exemplo é Vermelho
3, A Cor do Carro é Verde

Lista 2. Sequência de entrada

A Lista 3 mostra a saída da função mapear dessa entrada:

('This', 1), ('is', 1). ('Code', 1), ('Example', 1)
('Example', 1), ('Color', 1), ('is', 1), ('Red', 1)
('Car', 1), ('Color', 1), ('is', 1), ('Green', 1)

Lista 3. Saída da função mapear

A Lista 4 mostra a saída da função reduzir (do resultado):

('Car', 1), ('Code', 1), ('Color', 2), ('Example', 2), ('Green', 1), ('Red', 1)
, ('This', 1), ('is', 3)

Lista 4. Saída da função reduzir

Para os programadores, um principal recurso da estrutura do MapReduce é que há apenas dois primitivos declarativos de alto nível (map e reduce) que podem ser escritos em qualquer linguagem de programação escolhida, sem preocupações quanto aos detalhes de sua execução paralela. Por outro lado, o modelo de programação do MapReduce tem suas próprias limitações:

  1. Seu fluxo de dados de um entrada e dois estágios é extremamente rígido. Para executar tarefas que têm um fluxo de dados diferente (por exemplo, junções ou n estágios), é preciso desviar de soluções alternativas deselegantes;
  2. O código customizado é escrito até mesmo para as operações mais comuns (por exemplo, projeção e filtragem), o que faz com que o código seja geralmente difícil de reutilizar e manter;
  3. A natureza opaca das map e reduce funções impede a capacidade do sistema de executar otimizações.

Além disso, muitos programadores não estão familiarizados com a estrutura do MapReduce e preferem usar a SQL (porque são mais proficientes nela) como uma linguagem declarativa de alto nível para expressar sua tarefa e, ao mesmo tempo, deixar todos os detalhes de otimização da execução ao mecanismo de backend. Também é verdade que as abstrações de linguagem de alto nível permitem que o sistema subjacente execute melhor as otimizações automáticas.

A seguir, serão examinadas as linhas e sistemas desenvolvidos para lidar com esses problemas e incluir a SQL à estrutura do MapReduce.

Pig

O projeto Apache Pig é desenvolvido como um mecanismo para executar os fluxos de dados de modo paralelo ao Hadoop. Ele usa uma linguagem chamada Pig Latin para expressar esses fluxos de dados. Com a Pig Latin, é possível descrever como os dados de uma ou mais entradas devem ser lidos, processados e, depois, armazenados em uma ou mais saídas de modo paralelo. A linguagem toma uma posição intermediária entre a expressão de tarefas usando um modelo de consultas declarativo de alto nível similar à SQL e a programação procedural/de baixo nível que usa o MapReduce. Os fluxos de dados de Pig Latin podem ser fluxos lineares simples, mas também podem ser fluxos de trabalho complexos que incluem pontos nos quais há a junção de diversas entradas e nos quais os dados são divididos em diversos fluxos, a fim de serem processados por operadores diferentes.

Um programa de Pig Latin consiste de uma série de operações ou transformações que é aplicada aos dados de entrada a fim de produzir a saída. Consideradas como um todo, as operações descrevem um fluxo de dados que o ambiente de execução Pig traduz em uma representação que, depois, é executada. Em segundo plano, o Pig configura as transformações em uma série de tarefas do MapReduce.

Com o Pig, as estruturas de dados são muito mais ricas, geralmente têm diversos valores e aninhamentos; além disso, o conjunto de transformações que pode ser aplicado aos dados é muito mais eficiente. Em particular, o modelo de dados Pig Latin consiste dos quatro tipos a seguir:

  • Átomo é um valor atômico simples, como uma sequência ou um número; por exemplo, “John”;
  • Tupla é uma sequência de campos; cada um deles pode ser qualquer tipo de dado, por exemplo (“John”, “Melbourne”);
  • Pacote é uma coleção de tuplas com possíveis duplicados. O esquema de tuplas constituintes é flexível, no qual nem todas as tuplas de um pacote precisam ter o mesmo número e tipo de campos. O Pacote da Figura 1 lista duas tuplas: (“John”,”Melbourne”) e “Alice”,(“UNSW” “Sydney”);

  • Mapear é uma coleção de itens de dados, na qual cada um item tem uma chave associada por meio da qual ela pode ser procurada. Como ocorre com os pacotes, o esquema de itens de dados constituintes é flexível; no entanto, as chaves são necessárias para serem átomos de dados> O Mapa da Figura 2) lista os itens de dados: K1–>(“John”,”Melbourne”) e K2–>30.

A Pig Latin inclui operadores para muitas operações de dados tradicionais (join, sort, filter, group by, union, etc.), bem como a capacidade para que os usuários desenvolvam suas próprias funções para ler, processar e escrever dados.

O MapReduce fornece diretamente a operação group by (cujas fases de ordenação aleatória e redução são essenciais) e fornece a operação order by indiretamente por meio da maneira como implementa o agrupamento. A filtragem e a projeção podem ser implementadas de modo trivial na fase de mapeamento. No entanto, os outros operadores, principalmente join, não são fornecidos e, em vez disso, devem ser escritos pelo usuário. O Pig fornece implementações complexas e não triviais dessas operações de dados padrão. Por exemplo, devido ao fato de o número de registros por chave de um conjunto de dados ser raramente distribuído de modo uniforme, muitas vezes os dados enviados aos redutores são defasados. Ou seja, um redutor obterá 10 ou mais vezes a quantidade de dados que os outros. O Pig possui operadores join e order by que manipularão este caso e (em alguns casos) rebalanceará os redutores. Tablela 1 descreve os principais operadores da linguagem Pig Latin.

No MapReduce, o processamento de dados das fases de mapeamento e redução é opaco para o sistema. Isso significa que o MapReduce não tem oportunidade de otimizar ou verificar o código dos usuários. Por outro lado, o Pig pode analisar um script de Pig Latin e entender o fluxo de dados descrito pelo usuário. O MapReduce não tem um sistema de tipos. Isso é intencional e oferece aos usuários a flexibilidade para usar seus próprios tipos de dados e estruturas de serialização. A desvantagem é que isso limita ainda mais a capacidade do sistema de verificar o código do usuário em busca de erros antes e durante o tempo de execução. Todos esses pontos significam que a Pig Latin tem um custo muito menor para escrever e manter em relação ao código Java do MapReduce.

Operador Descrição
LOAD Carrega dados do sistema de arquivos ou outro armazenamento em uma relação
DUMP Imprime uma relação ao console FILTER do sistema
DISTINCT Remove as linhas duplicadas de uma relação
FOREACH … GENERATE Adiciona ou remove campos de uma relação
JOIN Junta duas ou mais relações
ORDER Classifica uma relação por um ou mais campos
LIMIT Limita o tamanho de uma relação a um número máximo de tuplas
STORE Salva uma relação no sistema de arquivos ou outro armazenamento
FILTER Remove as linhas indesejadas de uma relação
GROUP Agrupa os dados em uma única relação
CROSS Cria o produto cruzado de duas ou mais relações
UNION Combina duas ou mais relações em uma
SPLIT Divide uma relação em duas ou mais relações

Tablela 1. Os principais operadores da linguagem Pig Latin

A Lista 5 mostra um programa simples de Pig Latin para encontrar todos os funcionários com um salário alto.

employees = LOAD 'employee.txt' AS (id, name, salary);
highSalary = FILTER employees BY salary > 100000;
sortedList = ORDER highSalary BY salary DESC;
STORE sortedList INTO ' highSalary _Emp';
DUMP sortedList;

Lista 5. Encontrar todos os funcionários com salário alto

Neste exemplo, em primeiro lugar, carregue o arquivo de entrada em um pacote chamado employees. Depois, crie um novo pacote chamado highSalary, que contém apenas os registros cujo campo salary é superior a 100000. O pacote sortedList classifica os registros filtrados com base no valor do salário, em ordem descendente. Finalmente, escreva o conteúdo do pacote sortedList no HDFS e imprima o seu conteúdo na tela.

A Lista 6 mostra como descreverjunção as operações facilmente usando a Pig Latin.

employees = LOAD 'employee.txt' AS (id, name, salary, dept);
departments = LOAD 'dept.txt' AS (deptID, deptName);
joinList = JOIN employees BY dept, departments BY deptID;
STORE joinList INTO ' joinFile';

Lista 6. as operações join podem ser descritas facilmente usando a Pig Latin

Tradicionalmente, as consultas ad hoc são realizadas em idiomas como SQL, que facilitam a rápida formação de uma questão a ser respondida pelos dados. Para a pesquisa de dados brutos, alguns usuários preferem a Pig Latin. O Pig pode operar em situações cujo esquema é conhecido, incompleto ou inconsistente e, já que ele pode gerenciar facilmente os dados aninhados, os pesquisadores que desejam trabalhar nos dados antes de sua limpeza e carregamento no warehouse, muitas vezes, preferem o Pig. Os pesquisadores que trabalham com grandes conjuntos de dados, muitas vezes, usam linguagens de script como Perl ou Python para fazer seu processamento. Os usuários com esses planos de fundo preferem o paradigma de fluxo de dados do Pig do que o paradigma de consulta declarativa da SQL.

Hive

O projeto Apache Hive é uma solução de data warehousing de software livre construída pela Equipe de Infraestrutura de Dados do Facebook no ambiente Hadoop. O principal objetivo do projeto é levar conceitos de bancos de dados relacionais (por exemplo, tabelas, colunas, partições) e um subconjunto de SQL ao mundo desestruturado do Hadoop, ao mesmo tempo em que mantém a extensibilidade e a flexibilidade desfrutada no Hadoop. Assim, ele oferece suporte a todos os principais tipos primitivos (por exemplo, números inteiros, flutuações, sequências) e tipos complexos (por exemplo, mapas, listas, estruturas). O Hive oferece suporte às consultas expressas em HiveQL (Hive Query Language), uma linguagem declarativa similar à SQL e, portanto, pode ser entendido facilmente por qualquer pessoa familiarizada com a SQL. Essas consultas são compiladas automaticamente nas tarefas do MapReduce que são executadas usando Hadoop. Além disso, a HiveQL permite que os usuários realizem o plug in de scripts customizados de MapReduce nas consultas.

A HiveQL oferece suporte às instruções de Linguagem de Definição de Dados (DDL), que podem ser usadas para criar, eliminar e alterar as tabelas de um banco de dados. Ela permite que os usuários carreguem dados de fontes externas e insiram os resultados das consultas em tabelas do Hive por meio do carregamento e inserção de instruções de Linguagem de Manipulação de Dados (DML), respectivamente. No entanto, atualmente a HiveQL não oferece suporte à atualização e exclusão de linhas das tabelas existentes (em particular, as instruções INSERT, UPDATE e DELETE INTO), o que permite o uso de mecanismos bastante simples para lidar com operações simultâneas de leitura e gravação sem precisar implementar protocolos de bloqueio complexos. O componente de metaloja é o catálogo do sistema Hive, que armazena metadados sobre a tabela subjacente. Estes metadados são especificados durante a criação da tabela e são reutilizados sempre que é feita referência à tabela na HiveQL. A metaloja distingue o Hive como uma solução tradicional de warehousing em comparação aos sistemas similares de processamento de dados que são construídos em arquiteturas similares ao MapReduce, como a Pig Latin.

A Lista 7 mostra exemplos das instruções de HiveQL que descrevem as operações para criar uma tabela, carregar dados e consultar o conteúdo das tabelas.

CREATE TABLE employee (empID INT, name STRING, salary BIGINT)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;
LOAD DATA INPATH "employee_data" INTO TABLE employee;
SELECT * FROM employee WHERE salary > 100000 SORT BY salary DESC;

Lista 7. Instruções de HiveQL que descrevem as operações para criar uma tabela, carregar dados e consultar o conteúdo das tabelas

O Hive também oferece suporte à manipulação de dados por meio de funções criadas pelos usuários (veja a Lista 8).

INSERT OVERWRITE TABLE employee
SELECT
TRANSFORM (empID, name, salary, address, department)
USING 'python employee_mapper.py'
AS (empID, name, salary, city)
FROM employee_data;

Lista 8. O Hive oferece suporte aos dados de manipulação por meio de funções criadas por usuários

Em geral, o Hive é uma ótima interface para qualquer pessoa envolvida no mundo de bancos de dados relacionais, embora os detalhes da implementação subjacente não sejam completamente ocultos. Ainda é preciso se preocupar com algumas diferenças em termos da melhor maneira para especificar as junções para o melhor desempenho e alguns recursos ausentes de linguagem. O Hive oferece a capacidade de fazer plug in de códigos customizados para situações que não se ajustam à SQL, bem como muitas ferramentas para manipular as entradas e saídas. Ele sofre algumas limitações, como a falta de suporte às instruções UPDATE ou DELETE ,INSERT em linhas únicas, e tipos de dados de data ou horário, já que elas são tratadas como sequências.

HadoopDB

O projeto HadoopDB, comercializado pela empresa Hadapt, é um sistema híbrido que tenta combinar as vantagens de escalabilidade do MapReduce com as vantagens de desempenho e eficiência dos bancos de dados paralelos. A ideia básica por trás do HadoopDB é conectar diversos sistemas de bancos de dados de nó único (PostgreSQL) usando o Hadoop como o coordenador de tarefas e a camada de comunicação de rede. As consultas são expressas em SQL, mas suas execuções são paralelizadas entre os nós usando a estrutura do MapReduce, a fim de que seja realizado um único trabalho de consulta, no maior nível possível, no banco de dados do nó correspondente.

Em geral, os sistemas de bancos de dados paralelos estão comercialmente disponíveis há quase duas décadas e, agora, existe cerca de dúzias de implementações diferentes no mercado de trabalho (por exemplo, Teradata, Aster Data, Greenplum). O principal objetivo desses sistemas é melhorar o desempenho por meio da paralelização de várias operações como carregamento de dados, desenvolvimento de índices e avaliação de consultas. Em geral, alguns principais motivos tornam o MapReduce uma abordagem preferencial em relação aos RDBMS paralelos em alguns cenários:

  • Formatar e carregar uma grande quantia de dados em um RDBMS paralelo em tempo hábil é uma tarefa desafiadora e demorada;
  • Os registros de dados de entrada podem nem sempre seguir o mesmo esquema. Muitas vezes, os desenvolvedores querem a flexibilidade para incluir e eliminar atributos e a interpretação de um registro de dados de entrada sempre pode mudar ao longo do tempo;
  • O processamento de dados em grande escala pode ser bastante demorado e, portanto, é importante manter a tarefa de análise de modo contínuo, mesmo em caso de falhas. Embora a maioria dos RDBMSs paralelos tenha suporte de tolerância a falhas, geralmente uma consulta precisa ser reiniciada mesmo se houver falha de apenas um nó do cluster. Por outro lado, o MapReduce manipula as falhas de modo mais gracioso e pode refazer somente parte do cálculo que foi perdido por causa de uma falha.

A comparação entre a estrutura do MapReduce e os sistemas de bancos de dados paralelos é um debate de muito tempo. Tem existido uma comparação de grande escala entre a implementação Hadoop da estrutura do MapReduce e os sistemas de gerenciamento d e bancos de dados de SQL paralelos em termos de desempenho e complexidade de desenvolvimento. Os resultados mostram que os sistemas de bancos de dados paralelos têm uma vantagem significativa de desempenho em relação ao MapReduce, em termos de execução de uma variedade de tarefas de análise com dados intensos. Por outro lado, a implementação do Hadoop tem configuração e uso mais fácil e direto em comparação aos sistemas de bancos de dados paralelos. O MapReduce também mostrou um desempenho superior ao minimizar a quantia de trabalho perdida em caso de falha de hardware. Além disso, o MapReduce (com suas implementações de software livre) representa uma solução bastante barata em comparação às soluções paralelas de DBMS muito caras.

Originalmente, os principais aplicativos da estrutura do MapReduce tinha um foco na análise de conjuntos de dados muito grandes, tais como indexação de web, analítica de texto e mineração de dados de gráficos. Recentemente, à medida que o MapReduce apresenta um desenvolvimento estável ao padrão de análise de dados de facto, ele é implementado de modo contínuo para consultar dados estruturados. Por muito tempo, o banco de dados relacional dominou as implementações dos sistemas de data warehousing e o desempenho das tarefas analíticas de dados estruturados. Há um crescente interesse na combinação entre o MapReduce e os sistemas tradicionais de bancos de dados para manter os benefícios de ambos os mundos. Em particular, o HadoopDB tentar atingir a tolerância a falhas e a capacidade de operar em ambientes heterogêneos por meio da herança da implementação de planejamento e rastreamento de tarefas do Hadoop. Ele tenta atingir os benefícios de desempenho ao realizar a maioria do processamento de consultas dentro do mecanismo do banco de dados.

A Figura 3 demonstra a arquitetura do HadoopDB, que consiste de duas camadas: 1) Uma camada de armazenamento de dados ou HDFS e 2) Uma camada de processamento de dados ou a estrutura do MapReduce.

Figura 3. A arquitetura do HadoopDB

Nesta arquitetura, o HDFS é um sistema de arquivos estruturado em blocos e gerenciado por um Nó de Nomes central. Os arquivos individuais são quebrados em blocos com tamanho fixo e distribuídos entre os diversos Nós de Dados do cluster. O Nó de Nomes mantém os metadados sobre o tamanho e localização dos blocos, bem como suas réplicas. A estrutura do MapReduce segue uma arquitetura simples de mestre-escravo. O mestre é um Rastreador de Trabalhos simples e os nós escravos ou de trabalhadores são Rastreadores de Tarefas. O Rastreador de Trabalhos manipula o planejamento de tempo de execução das tarefas do MapReduce e mantém informações sobre cada carregamento e recursos disponíveis do Rastreador de Tarefas. O Conector do Banco de Dados é a interface entre os sistemas de bancos de dados independentes que residem nos nós do cluster e os Rastreadores de Tarefas. Ele se conecta ao banco de dados, executa a consulta de SQL e exibe os resultados como pares de valores de chave. O componente de Catálogo mantém os metadados sobre os bancos de dados, sua localização, as localizações das réplicas e as propriedades de partição dos dados. O componente de Carregador de Dados é responsável pelos dados globais de repartição de determinada chave de partição após o carregamento e quebra dos dados de um único nó em diversas partições ou chunks menores. O planejador de SMS estende o conversor de HiveQL e transforma a SQL em tarefas do MapReduce que se conectam às tabelas armazenadas como arquivos no HDFS.

Jaql

Jaql é uma linguagem de consultas desenvolvida para JavaScript Object Notation (JSON), um formato de dados popular por causa de sua simplicidade e flexibilidade de modelagem. A JSON é uma maneira simples, mas flexível de representar os dados que variam de dados simples a dados XML semiestruturados. A Jaql é usada principalmente para analisar dados semiestruturados de grande escala. E é uma linguagem de consulta declarativa e funcional que regrava as consultas de alto nível, quando adequado, em uma consulta de baixo nível que consiste de tarefas do MapReduce que são avaliadas usando o projeto Apache Hadoop. Os principais recursos incluem a extensibilidade e o paralelismo de usuários. A Jaql consiste de uma linguagem de script e um compilador, bem como um componente de tempo de execução. Ela consegue realizar um processo que não tem qualquer esquema ou que tem apenas um esquema parcial. No entanto, a Jaql também pode explorar as informações de esquemas rígidos, quando disponíveis, para verificação de tipos e um melhor desempenho. O fragmento a seguir da Lista 9 mostra uma amostra de documento de JSON.

[
{ id: 10,
name: "Joe Smith",
email: "JSmith@email.com",
zip: 85150
},
{ id: 20,
name: "Alice Jones",
email: "AJones@email.com",
zip: 82116
}
]

Lista 9. Amostra de documento de JSON

A Jaql usa um modelo de dados muito simples, um valor de JDM (Modelo de Dados de Jaql) que é um átomo, uma matriz ou um registro. Os tipos atômicos mais comuns são suportados, incluindo sequências, números, valores nulos e datas. As matrizes e registros são tipos compostos que podem ser aninhados de modo arbitrário. De modo mais detalhado, uma matriz é uma coleção ordenada de valores que pode ser usada para modelar as estruturadas de dados como vetores, listas, conjuntos ou pacotes. Um registro é uma coleção não ordenada de pares de valores de nomes que pode modelar estruturas, dicionários e mapas. Apesar de sua simplicidade, o JDM é bastante flexível. Ele permite que a Jaql opere com uma variedade de diferentes representações de dados para entrada e saída, incluindo arquivos de texto delimitado, arquivos de JSON, arquivos binários, Arquivos de Sequência da Hardtop, bancos de dados relacionais, armazenamentos de valores de chave ou documentos XML. As funções são valores de primeira classe na Jaql. Elas podem ser designadas a uma variável e têm alta ordem, podendo ser passadas como parâmetros ou usadas como um valor de retorno. As funções são o principal ingrediente para a possibilidade de reutilização, já que qualquer expressão de Jaql pode ser contida em uma função e que uma função pode ser parametrizada em maneiras poderosas. A Lista 10 é um exemplo de um script de Jaql que consiste de uma sequência de operadores.

import myrecord;
countFields = fn(records) (
records
-> transform myrecord::names($)
-> expand
-> group by fName = $ as occurrences
into { name: fName, num: count(occurrences) }
);
read(hdfs("docs.dat"))
-> countFields()
-> write(hdfs("fields.dat"));

Lista 10. Script de Jaql que consiste de uma sequência de operadores

O operador de leitura carrega os dados brutos, neste caso a partir do Sistema de Arquivos Distribuídos do Hadoop (HDFS), e os converte em valores de Jaql. Estes valores são processados pelo subfluxo countFields, que extrai os nomes de campos e calcula as suas frequências. Finalmente, o operador de gravação armazena o resultado de volta no HDFS. A Tablela 2 descreve as principais expressões da linguagem de script Jaql.

Expressão Descrição
transform A expressão transform aplica uma função (ou projeção) a todos os elementos de uma matriz, a fim de produzir uma nova matriz.
expand A expressão expand é usada com frequência para desaninhar sua matriz de entrada.
group by Similar à GROUP BY da SQL, a expressão group by da Jaql particiona a sua entrada em uma expressão de agrupamento e aplica uma expressão de agregação a cada grupo.
Filter A expressão filter retém os valores de entrada cujo predicado específico é avaliado como verdadeiro.
Join A expressão join oferece suporte à junção equivalente de 2 ou mais entradas. Todas as opções de junções internas e externas também são suportadas.
Union A expressão union é uma função da Jaql que mescla diversas matrizes de entrada em uma única matriz de saída.
Control-flow As duas expressões de fluxo de controle mais usadas da Jaql são as expressões if-then-else e de bloco. A expressão if-then-else é similar às expressões condicionais encontradas na maioria das linguagens de script e programação. Um bloco estabelece um escopo local no qual as variáveis zero ou mais locais podem ser declaradas e a última instrução fornece o valor de retorno do bloqueio.

Tablela 2. Principais expressões da linguagem de script Jaql

Em alto nível, a arquitetura da Jaql representada na Figura 4 é similar à maioria dos sistemas de bancos de dados.

Figura 4. A arquitetura do sistema da Jaql

Os scripts são passados ao sistema a partir do interpretador ou de um aplicativo, são compilados pelo analisador e pelo mecanismo de regravação e explicados ou avaliados sobre os dados da camada de E/S. A camada de armazenamento é similar a um banco de dados federado. Ela fornece uma API para acessar os dados a partir de sistemas diferentes, incluindo sistemas de arquivos distribuídos ou locais (como o HDFS do Hadoop), sistemas de bancos de dados (como DB2, Netezza, HBase) ou a partir de fontes em fluxo como a web. No entanto, ao contrário dos bancos de dados federados, a maioria dos dados acessados é armazenada no mesmo cluster e a API de E/S descreve a partição de dados, o que ativa um paralelismo com a afinidade de dados durante a avaliação. A Jaql deriva boa parte dessa flexibilidade da API de E/S do Hadoop. Ela lê e grava muitos formatos de arquivos comuns (como arquivos delimitados, textos de JSON e arquivos de Sequência de Hadoop). Os adaptadores customizados são facilmente gravados para mapear um conjunto de dados para ou a partir do modelo de dados de Jaql. A entrada pode ser até mesmo valores construídos no próprio script. O interpretador de Jaql avalia o script localmente no computador que compilou este script, mas faz o spawn dos interpretadores nos nós remotos usando o MapReduce. O compilador de Jaql detecta automaticamente as oportunidades de paralelização de um script de Jaql e o converte em um conjunto de tarefas do MapReduce.

Conclusão

O MapReduce surgiu como uma maneira popular para proteger o poder dos grandes clusters de computadores. Atualmente, ele serve como uma plataforma para uma quantia considerável de análises de dados massivos. Ele permite que os programadores pensem de modo centralizado nos dados e possam focar na aplicação de transformações aos conjuntos de registros de dados, ao mesmo tempo em que os detalhes da execução distribuída e da tolerância a falhas são gerenciados de modo transparente pela estrutura do MapReduce. Na prática, muitos programadores preferem usar linguagens declarativas de alto nível (ou similares à SQL) para implementar suas tarefas paralelizadas de análise de dados em grande escala, ao mesmo tempo em que deixam todos os detalhes de otimização da execução ao mecanismo de backend. Neste artigo, foi apresentada uma visão geral de ponta das interfaces declarativas de alto nível para a estrutura do MapReduce. Minimize seus ônus com programação com as abstrações de linguagens de alto nível que permitem que os sistemas subjacentes executem otimizações automáticas no nível de execução e melhorem o desempenho das tarefas dos usuários.

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Sobre o autor: Sherif Sakr é Cientista de Pesquisa do Software Systems Group do National ICT Australia (NICTA), Sydney, Austrália. Ele também é Palestrante Conjunto da School of Computer Science and Engineering (CSE) da Universidade de New South Wales (UNSW). Recebeu o título de PhD em Ciências da Computação na Universidade de Konstanz, Alemanha, em 2007. Além disso, graduou-se e recebeu o título mestre em Ciências da Computação no departamento de Sistemas da Informação da Faculty of Computers and Information da Universidade do Cairo, Egito, em 2000 e 2002, respectivamente. Em 2011, Dr. Sakr ocupou o cargo de cientista de pesquisa visitante na eXtreme Computing Group (XCG) na Microsoft Research, Redmond, EUA. É desenvolvedor certificado pela Cloudera em Apache Hadoop.