Use o InfoSphere BigInsights para Consultar Mídias Sociais e Dados Estruturados

Introdução ao Jaql

Se você deseja iniciar rapidamente os seus projetos de Big Data envolvendo o IBM® InfoSphere® BigInsights™, é importante aprender o básico sobre como consultar, manipular e analisar os dados. Este artigo guia você por exemplos de consultas simples que mostram como ler, gravar, filtrar e refinar dados estruturados e de mídia social. Você verá, inclusive, como os analistas de negócios podem visualizar os resultados de consulta usando uma ferramenta com o estilo de planilha.

Cynthia M. Saracco, Senior Solutions Architect, IBM

Cynthia SaraccoCynthia M. Saracco é arquiteta de soluções senior no Laboratório da IBM no Vale do Silício e especialista em tecnologias emergentes e gerenciamento de informações. Ela tem 25 anos de experiência no segmento de mercado de software, escreveu três livros e mais de 70 documentos técnicos e detém sete patentes.


nível de autor Profissional do
        developerWorks

Marcel Kutsch, Software Engineer, IBM

Marcel Kutsch é engenheiro de software do grupo Big Data no Laboratório da IBM no Vale do Silício, em San José, CA. Atualmente, ele trabalha no desenvolvimento do tempo de execução do Jaql. Antes disso, trabalhou por cinco anos no desenvolvimento do DB2, desempenhando várias funções. Marcel é coautor de um IBM Redbook sobre o desenvolvimento do procedimento armazenado do DB2 z/OS e possui várias patentes na área de tecnologia de banco de dados.



24/Ago/2012

O trabalho com Big Data muitas vezes precisa da consulta desses dados para isolar as informações de interesse e manipulá-las de várias formas. Este artigo apresenta o Jaql, uma linguagem de consulta e script fornecida com o InfoSphere BigInsights. Também mostra como consultar dados coletados de um site de mídia social e unir esses dados com informações recuperadas de um sistema de gerenciamento de banco de dados relacional (DBMS).

Plano de fundo

O InfoSphere BigInsights é uma plataforma de software projetada para ajudar as empresas a descobrir e analisar insights de negócios ocultos em grandes volumes de um intervalo heterogêneo de dados que muitas vezes é ignorado ou descartado porque o seu processamento pelos meios tradicionais é difícil ou pouco prático. Entre os exemplos desses dados estão registros de log, fluxos de cliques, dados de mídia social, feeds de notícias, saída de sensor eletrônico e até mesmo alguns dados transacionais.

Para ajudar as empresas a gerar valor a partir desses dados de uma maneira eficiente, a Enterprise Edition do BigInsights inclui vários projetos de software livre (inclusive o Apache™ Hadoop™) e várias tecnologias desenvolvidas pela IBM. O Hadoop e seus projetos complementares fornecem uma estrutura de software efetiva para aplicativos com intensidade de dados que exploram ambientes de computação distribuídos para alcançar alta escalabilidade. As tecnologias IBM enriquecem essa estrutura de software livre com software analítico, integração corporativa de software, extensões de plataformas e ferramentas. Para saber mais sobre o BigInsights, consulte a seção Recursos .

Este artigo apresenta recursos básicos de consulta fornecidos com o BigInsights por meio do Jaql, uma linguagem de script e consulta com um modelo de dados baseado no JavaScript Object Notation (JSON). Embora o Jaql não seja a única forma de consultar dados gerenciados pelo BigInsights Basic ou Enterprise Edition (por exemplo, é possível usar o Hive ou Pig), ele funciona bem com várias estruturas de dados, inclusive com as perfeitamente aninhadas. O BigInsights também inclui um módulo de Jaql para acessar origens de dados habilitadas para JDBC. Esses recursos são particularmente úteis para o nosso cenário, que envolve analisar um pequeno conjunto de dados de mídia social coletado como registros de JSON e combinar esses dados com registros corporativos extraídos de um DBMS relacional em um formato em CSV (valores separados por vírgula) usando o módulo de JDBC do Jaql.

Entendendo o cenário de exemplo

Neste artigo, o Jaql será usado para coletar publicações sobre o IBM Watson a partir de um site de mídia social e, em seguida, chamar várias expressões do Jaql para filtrar, transformar e manipular esses dados. O IBM Watson é um projeto de pesquisa que realiza analítica complexa para responder perguntas apresentadas em um idioma natural. Para fazer isso, o software do Watson usa o Apache Hadoop executando em um cluster de servidores IBM Power 750 para processar eficientemente os dados coletados de várias fontes. Em 2011, o IBM Watson ficou em primeiro lugar no programa de televisão Jeopardy! (uma competição de perguntas e respostas), derrotando os dois principais competidores humanos. Consulte a seção Recursos para obter mais detalhes sobre o IBM Watson.

Em muitas empresas, os analistas de negócios estão interessados em monitorar a visibilidade, cobertura e repercussão de um determinado serviço ou marca. Por isso, o IBM Watson será usado como exemplo de marca neste artigo. Um artigo anterior, citado na seção Recursos , mostrou como os analistas de negócios podem usar o BigSheets, uma ferramenta estilo planilha fornecida com o BigInsights, para analisar os dados na mídia social sobre o IBM Watson que foram coletados em diversos sites. Neste artigo, um pequeno conjunto de dados de um site (Twitter) será coletado e trabalhado, para ser possível focar o aprendizado de aspectos importantes do Jaql.

Vale ressaltar que muitos sites de mídia social oferecem APIs que os programadores podem usar para obter dados públicos. Neste artigo, a API de procura baseada em REST do Twitter será usada para recuperar uma pequena quantidade de dados contendo tweets recentes e relevantes. Um aplicativo de produção provavelmente usaria outros serviços do Twitter para obter grandes volumes de dados. No entanto, já que o foco deste artigo é o Jaql, o trabalho de coleta de dados é feito de forma simples.

Com frequência, as APIs oferecidas por sites de mídia social retornam dados como JSON, o mesmo modelo de dados no qual o Jaql se baseia. Antes de se aprofundar nos exemplos do Jaql, é preciso se familiarizar com a estrutura JSON dos dados de mídia social que serão trabalhados neste artigo. É possível fazer isso facilmente digitando a seguinte URL em um navegador da web que pode processar dados de JSON (como o Chrome): http://search.twitter.com/search.json?q=IBM+Watson.

Isso faz com que o Twitter retorne as 15 publicações mais recentes correspondentes aos seus critérios de procura ("IBM Watson"). Embora o conteúdo retornado varie dependendo do momento da realização da procura, a estrutura dos resultados será semelhante ao extrato mostrado na Listagem 1, que inclui dados de amostra criados para fins ilustrativos. A seguir, alguns aspectos importantes desse extrato serão explorados para contextualizar de maneira adequada o restante do artigo.

Lista 1. Amostra da estrutura de registro do JSON proveniente de uma procura baseada no Twitter
{
    "completed_in": 0.021,
    "max_id": 99999999111111,
    "max_id_str": "99999999111111",
    "next_page": "?page=2&max_id=99999999111111&q=IBM%20Watson",
    "page": 1,
    "query": "IBM+Watson",
    "refresh_url": "?since_id=99999999111111&q=IBM%20Watson",
    "results": [
    {
        "created_at": "Mon, 30 Apr 2012 18:42:37 +0000",
        "from_user": "SomeSampleUser",
        "from_user_id": 444455555,
        "from_user_id_str": "444455555",
        "from_user_name": "Some Sample User",
        "geo": null,
        "id": 000000000000000001,
        "id_str": "000000000000000001",
        "iso_language_code": "en",
        "metadata": {
            "result_type": "recent"
        },
        "profile_image_url": 
            "http://a0.twimg.com/profile_images/222222/TwitterPic2_normal.jpg",
        "profile_image_url_https": 
            "https://si0.twimg.com/profile_images/222222/TwitterPic2_normal.jpg",
        "source": "<a href="http://news.myUniv.edu/" rel="nofollow">MyUnivNewsApp</a>",
        "text": "RT @MyUnivNews: IBM's Watson Inventor will present at 
          a conference April 12   http://confURL.co/xrr5rBeJG",
        "to_user": null,
        "to_user_id": null,
        "to_user_id_str": null,
        "to_user_name": null
    },
                
    {
        "created_at": "Mon, 30 Apr 2012 17:31:13 +0000",
        "from_user": "anotheruser",
        "from_user_id": 76666993,
        "from_user_id_str": "76666993",
        "from_user_name": "Chris",
        "geo": null,
        "id": 66666536505281,
        "id_str": "66666536505281",
        "iso_language_code": "en",
        "metadata": {
        "result_type": "recent"
    },
        "profile_image_url": 
            "http://a0.twimg.com/profile_images/3331788339/Mug_Shot.jpg",
        "profile_image_url_https": 
            "https://si0.twimg.com/profile_images/3331788339/Mug_Shot.jpg",
        "source": "<a href="http://www.somesuite.com" rel="nofollow">SomeSuite</a>",
        "text": "IBM's Watson training to help diagnose and treat cancer 
            http://someURL.co/fBJNaQE6",
        "to_user": null,
        "to_user_id": null,
        "to_user_id_str": null,
        "to_user_name": null
},
. . . 
"results_per_page": 15,
"since_id": 0,
"since_id_str": "0"
}

Segue uma introdução muito breve do JSON. A Listagem 1 contém um registro do JSON, conforme indicam as chaves "{ }" no início e no final. Dentro desse registro, há vários pares nome/valor, registros JSON adicionais (aninhados) e arrays de JSON (que ficam entre colchetes, "[ ]"). Isso é típico do JSON, que acomoda estruturas de dados muito aninhadas e variadas. Para conhecer mais detalhes sobre o JSON, consulte a seção Recursos .

Observando esse exemplo, é possível ver que a parte inicial do registro JSON contém pares nome/valor com informações de plano de fundo sobre a procura no Twitter. Por exemplo, a procura foi concluída em 0,021 segundo e a consulta envolveu o IBM Watson. O array de "resultados" aninhado dentro do registro contém os dados de maior interesse para este artigo: registros JSON adicionais com tweets sobre o IBM Watson.

Cada um dos registros JSON aninhados no array de resultados indica o nome pelo qual o usuário é conhecido ("from_user_name"), o registro de data e hora da criação da mensagem ("created_at"), o texto da mensagem ("text"), o idioma do texto "iso_language_code", etc. Na verdade, o ID de usuário ("from_user_id_str") será usado para juntar os dados de mídia social com os dados extraídos de um DBMS relacional. O cenário de junção deste artigo será muito simples e, talvez, até um pouco forçado. Ele supõe que um empregador mantenha uma tabela relacional que controla os IDs de mídia social que os seus funcionários usam para fazer negócios oficiais e que a empresa quer analisar as publicações recentes deles. No entanto, a abordagem básica de usar o Jaql para juntar dados de diversas origens pode ser aplicada a uma ampla variedade de cenários.


Executando instruções do Jaql

O BigInsights Enterprise Edition fornece diversas opções para executar instruções do Jaql, incluindo as seguintes:

  • Shell do Jaql, uma interface da linha de comandos.
  • Aplicativo de consulta ad hoc do Jaql, que pode ser acessado por meio do console da web do BigInsights. Para ser possível ativar esse aplicativo, o administrador deve implementá-lo no cluster do BigInsights e autorizar o acesso ao aplicativo. Consulte a seção Recursos para ver o link de um artigo separado sobre o console da web do BigInsights e aplicativos de amostra.
  • Ambiente de teste do Jaql fornecido com as ferramentas Eclipse para o BigInsights.
  • O servidor da web do Jaql, que permite executar scripts de Jaql por meio de chamadas da API de REST.
  • API do Jaql para integrar o Jaql a um programa Java.

Este artigo usa o shell do Jaql. Para ativá-lo, abra uma janela de comando do Unix/Linux e execute o comando a seguir: $BIGINSIGHTS_HOME/jaql/bin/jaqlshell

Observe que $BIGINSIGHTS_HOME é uma variável de ambiente definida de acordo com o diretório em que o BigInsights foi instalado, normalmente em /opt/ibm/biginsights. Depois da ativação do shell do Jaql, a tela deve ficar semelhante à Figura 1.

Figura 1. Shell do Jaql
Shell do Jaql

Jaql e MapReduce

Jaql foi projetado para explorar de forma transparente o modelo de programação do MapReduce, que está associado a ambientes baseados no Hadoop. Com o Jaql, é possível focar no problema que você está tentando resolver, e não na implementação subjacente do seu trabalho. Em outras palavras, as suas consultas especificam o que você quer fazer, e o mecanismo do Jaql reescreve de forma transparente as suas consultas para determinar como o trabalho será realizado. A tecnologia de reescrita de consultas é comum em ambientes de sistema de gerenciamento de banco de dados relacional (RDBMS), e o Jaql utiliza essa ideia fundamental para simplificar o seu trabalho.

Frequentemente, uma parte de tecnologia de reescrita de consultas do Jaql envolve a divisão da lógica em várias tarefas de Map e Reduce, para que o seu trabalho possa ser processado em paralelo no cluster do BigInsights. As consultas que podem ser reescritas dessa forma são chamadas de divisíveis ou particionáveis. Depois que você estiver familiarizado com o Jaql, este artigo tratará dos tipos de consultas que o Jaql pode converter em uma sequência de tarefas de MapReduce.

Coletando dados de amostra

A consulta, a manipulação e a análise de dados por meio do Jaql começam com a leitura dos dados a partir da origem, que pode ser o Hadoop Distributed File System (HDFS) gerenciado pelo BigInsights, um sistema de arquivos local, um DBMS relacional, um site de mídia social com uma API de procura baseada em REST e outras origens. Nesta seção, você aprenderá a usar o Jaql para preencher o HDFS com dados de JSON recuperados do Twitter e com dados relacionais recuperados do DB2 Express-C. Embora o BigInsights suporte outros mecanismos de coleta e carregamento de dados, as técnicas descritas aqui são adequadas para o cenário de aplicativo simples deste artigo e têm o objetivo de apresentar os principais recursos do Jaql.

Trabalhando com dados de mídia social

O BigInsights inclui vários adaptadores de E/S para o Jaql. Cada adaptador manipula o acesso a uma origem de dados específica, como HDFS, um servidor da web ou um banco de dados e converte os dados entre seu formato nativo e arrays de valores de JSON. Como você pode imaginar, os adaptadores de E/S do Jaql estão estreitamente ligados às funções read() e write() fornecidas pela linguagem.

Agora explore uma forma simples de recuperar as 15 mensagens mais recentes do Twitter sobre o "IBM Watson". Como mostra a Listagem 2, primeiro uma variável url é definida para a URL do Twitter que será usada para recuperar os dados de interesse. Em seguida, uma variável tweets é definida, designando a ela uma expressão que usa a função read() do Jaql com o adaptador de HTTP para obter dados a partir da URL especificada.

Lista 2. Usando o adaptador de HTTP do Jaql para realizar o fluxo de dados a partir de uma URL
url = "http://search.twitter.com/search.json?q=IBM+Watson"; 
                
tweets = read(http(url));
                
tweets;

Já que o Jaql materializa designações de variáveis de forma preguiçosa, a operação de leitura pode não ocorrer antes da execução da última instrução. A inserção de uma variável no shell do Jaql instrui o programa a exibir o conteúdo da variável, forçando a avaliação da operação que a define.

Embora o uso de variáveis seja opcional, muitas vezes é prático, porque as consultas subsequentes podem referenciar essas variáveis para simplificar o código. De fato, várias listagens que serão mostradas mais adiante neste artigo irão fazer referência a uma variável definida anteriormente para ilustrar esse ponto.

Os resultados da execução das instruções mostradas anteriormente na Listagem 2 serão semelhantes ao conteúdo da Listagem 1. Como acontece em todos os exercícios deste artigo, os resultados específicos variam, porque os tweets mais recentes sobre o IBM Watson variam com o tempo. Entretanto, há uma diferença entre os dados retornados pelas duas listagens. O Jaql integra os dados retornados pelo serviço da web em um array de nível superior, por exemplo, [ twitter-json-data-content ]. Sendo assim, os tweets representam um array que contém um registro JSON com a estrutura mostrada anteriormente na Listagem 1.

Trabalhando com dados de DBMS relacional

O BigInsights Enterprise Edition inclui aplicativos de importação e exportação de banco de dados que podem ser ativados a partir do console da web para ler em DBMSs relacionais ou gravar neles. Artigos anteriores (mencionados na seção Recursos ) descreveram esses aplicativos de amostra e exemplificaram o uso do aplicativo de importação de banco de dados para recuperar dados no DB2 Express-C.

Neste artigo, o shell do Jaql será usado para recuperar dados de um DBMS relacional dinamicamente. O Jaql fornece conectividade de JDBC para DBMSs da IBM e de outras empresas, como o Netezza, DB2, Oracle, Teradata e outros. O módulo de conectividade do JDBC será usado para acessar um banco de dados do DB2 Express-C que contém uma tabela chamada IBM.TWEETERS. Ela controla os endereços de email, IDs do Twitter, nomes e cargos de funcionários da IBM que publicam mensagens nesse site de mídia social. A tabela neste artigo contém dados de amostra criados para fins de teste.

Agora, explore o código do Jaql mostrado na Listagem 3.

Lista 3. Consultando um DBMS relacional dinamicamente a partir do shell do Jaql
// Block 1: Import Jaql JDBC module
import dbms::jdbc; 
                
// Block 2: Set class path for JDBC drivers 
addRelativeClassPath(getSystemSearchPath(), '/home/hdpadmin/myDrivers/db2jcc4.jar');   
                
addRelativeClassPath(getSystemSearchPath(),  
'/home/hdpadmin/myDrivers/db2jcc_license_cu.jar');
                
// Block 3: Establish a database connection 
db := jdbc::connect(
   driver = 'com.ibm.db2.jcc.DB2Driver',
   url = 'jdbc:db2://myserver.ibm.com:50000/sample',
   properties = { user: "myID", password: "myPassword" }
);
                
// Block 4: Prepare and execute the query
desc := jdbc::prepare(db, query =
   "SELECT EMAIL, ID, NAME, TITLE FROM IBM.TWEETERS");
                
ibm = read(desc);
                
ibm; 
                
// Sample output 
[
    {
        "EMAIL": "john.doe@us.ibm.com",
        "ID": "1111111",
        "NAME": "John Doe",
        "TITLE": "Researcher"
    },
. . . 
    {
        "EMAIL": "mary.johnson@us.ibm.com",
        "ID": "71717171",
        "NAME": "Mary Johnson",
        "TITLE": "IT Architect"
    }
]

O Bloco 1 importa o módulo Jaql de interesse. Nesse caso, dbms é o nome de um pacote do Jaql que contém diversos conectores de DBMS implementados como módulos individuais. A instrução import coloca todas as funções e variáveis do módulo JDBC disponíveis para a sua sessão. A definição de escopo de desenvolvimentos de Jaql do JDBC é realizada pelo JDBC. Consulte as chamadas mostradas nos Blocos 3 e 4 da Listagem 3.

O Bloco 2 especifica os locais dos arquivos JAR obrigatórios do driver JDBC e os inclui no caminho da classe do Jaql. Já que ele está acessando o DB2 Express-C, os arquivos db2jcc4.jar e db2cc_license_cu.jar são copiados para um sistema de arquivos local. Em seguida, o Bloco 3 chama a função connect() do módulo de JDBC do Jaql, passando os parâmetros necessários de conectividade JDBC, como a classe do driver JDBC, a URL do JDBC, o nome e a senha do usuário. Observe que o operador de designação referente à variável db declarada nessa instrução parece diferente do operador da Listagem 2. Especificamente, o operador := mostrado aqui força o trabalho no lado direito da equação, o trabalho de conectividade do DBMS, para ser materializado imediatamente. Nesse caso, força o Jaql a tentar obter uma manipulação de conexões do DB2 imediatamente e a designa para a variável db .

Ao estabelecer uma conexão bem-sucedida com o banco de dados, é possível preparar e executar uma consulta, conforme mostrado no Bloco 4. Nesse exemplo, a instrução SQL SELECT simplesmente recupera quatro colunas de uma tabela. Observe que o módulo de JDBC do Jaql não analisa a consulta nem verifica sua sintaxe antes de passá-lo para o banco de dados de destino. A função read() do Jaql executa a consulta preparada, fazendo com que os resultados sejam exibidos como um array de JSON formado por vários registros, cada um com quatro campos que mapeiam para as quatro colunas especificadas na consulta SQL.

A partir do BigInsights 1.4, o conector de JDBC do Jaql oferece a opção de referenciar um arquivo de propriedades no armazenamento de credenciais do BigInsights que contém informações de conectividade com o DBMS (como um ID do usuário e senha válidos) em vez de passar esses dados diretamente, conforme mostrado anteriormente na Listagem 3. Para obter mais detalhes, consulte BigInsights InfoCenter na seção Recursos .

Agora que você sabe recuperar dados relacionais e de mídia social, esse conhecimento será utilizado um pouco mais adiante no artigo para juntar dados dessas origens diferentes usando o Jaql. Entretanto, primeiro, é necessário revisar alguns recursos básicos de consulta do Jaql.

Consultando e manipulando dados

Uma operação de consulta comum envolve a extração de campos específicos dos dados de entrada. Se você conhece SQL, pode considerar isso como a projeção ou recuperação de um subconjunto de colunas de uma tabela. Agora, veja como é possível recuperar campos específicos dos dados de amostra do Twitter coletados na seção anterior. Em seguida, veja como manipular ou transformar a sua saída em estruturas de JSON diferentes para atender às necessidades específicas do aplicativo.

Recuperando um único campo

Comece com um exemplo muito simples. Quando o código do Jaql mostrado anteriormente na Listagem 2 foi executado, o resultado obtido foi um array de JSON de nível superior que continha um registro JSON com dados acerca de publicações recentes sobre o IBM Watson retornadas pelo Twitter. (A Listagem 1 inclui dados de amostra de um registro JSON desse tipo retornado pelo Twitter.) No registro JSON, estava incluído um array de resultados formado por vários registros JSON que representam tweets. Cada registro desse tipo continha vários campos. E se você quisesse obter só um campo de cada registro, como o campo id_str ? Como você faria isso no Jaql?

A Listagem 4 mostra uma abordagem a uma consulta desse tipo, seguida por uma saída de amostra.

Lista 4. Recuperando um único campo por meio da expressão de transformação do Jaql
tweets -> transform $.results.id_str;
                
// Sample Jaql output 
[
    [
        "999992200059387904",
        "999992003644329985",
        "999991910044229633",
        "999991880671531008",
        "999991865702064128",
        "999991853391769601",
        "999991708440817664",
        "999991692309524480",
        "999991655370293248",
        "999991582779469826",
        "999991442597437442",
        "999991361437655041",
        "999991343142100992",
        "999991269276213249",
        "999991175747436544"
    ]
]

Vamos repassar brevemente a consulta. Como resultado da execução do código da Listagem 2, a variável tweets representa dados coletados da web. O operador de canal (->) alimenta esses dados para a expressão transform do Jaql, que altera a saída de acordo com as instruções. Nesse caso, o Jaql é instruído a recuperar o campo id_str contido no array de resultados dentro do registro atual. O cifrão mostrado na Listagem 4 é a abreviação do registro atual no Jaql.

Se a saída for analisada, será possível ver que ele contém um array de JSON retornado dentro de outro array do JSON. A expressão transform do Jaql itera e transforma todos os elementos de um array de entrada e retorna um array de saída. Nesse caso, a entrada fornecida consistia em um array com um único registro JSON, mas o registro continha um array aninhado nele. Assim, o Jaql retornou um array que incluía um único array (aninhado) de valores de id_str.

Agora, imagine que você preferiria um array simples de valores. A expressão expand do Jaql permite atingir esse objetivo. A expressão expand considera como entrada um array de arrays aninhados [ [ T ] ] e produz um array de saída [ T ] promovendo os elementos de cada array aninhado para a matriz de saída de nível superior. A Listagem 5 mostra como usar expand para retornar um único array com valores de id_str.

Lista 5. Simplificando um array aninhado com a expressão expand
tweets -> transform $.results.id_str -> expand;
                
// Sample Jaql output
[
    "999992200059387904",
    "999992003644329985",
    "999991910044229633",
    "999991880671531008",
    "999991865702064128",
    "999991853391769601",
    "999991708440817664",
    "999991692309524480",
    "999991655370293248",
    "999991582779469826",
    "999991442597437442",
    "999991361437655041",
    "999991343142100992",
    "999991269276213249",
    "999991175747436544"
]

Gravando e lendo dados de HDFS

Neste ponto, dados que foram recuperados dinamicamente estão sendo consultados a partir de uma origem da web. Embora seja possível continuar fazendo isso, pode ser mais prático gravar os dados de interesse no HDFS para que eles estejam disponíveis depois que a sessão do Jaql for fechada. Já que seu interesse é somente consultar os dados contidos no array de resultados aninhados retornado pelo Twitter, esses dados são gravados apenas no HDFS.

A Listagem 6 usa a função write() do Jaql para gravar alguns dos dados do Twitter em um SequenceFile chamado recentTweets.seq em um diretório específico do HDFS. Os SequenceFiles estão entre os diversos formatos suportados pelo Jaql.

Lista 6. Gravando dados em um SequenceFile
// Write the "results" data of the first element of tweets to HDFS 
// This data contains Twitter posts and related info  
tweets[0].results -> 
write(seq("/user/idcuser/sampleData/twitter/recentTweets.seq"));
                
// Jaql output
{
    "inoptions": {
        "adapter": "com.ibm.jaql.io.hadoop.DefaultHadoopInputAdapter",
        "configurator": "com.ibm.jaql.io.hadoop.FileInputConfigurator",
        "format": "org.apache.hadoop.mapred.SequenceFileInputFormat"
    },
    "location": "/user/idcuser/sampleData/twitter/recentTweets.seq",
    "outoptions": {
        "adapter": "com.ibm.jaql.io.hadoop.DefaultHadoopOutputAdapter",
        "configurator": "com.ibm.jaql.io.hadoop.FileOutputConfigurator",
        "format": "org.apache.hadoop.mapred.SequenceFileOutputFormat"
    }
}

A primeira linha da Listagem 6 especifica os dados a serem gravados: a parte de resultados do primeiro elemento no array de tweets retornado pela nossa procura no Twitter. Use a nota típica de índice de matriz para acessar o primeiro e único elemento do array de nível superior retornado pela variável tweets avaliada. Assim, tweets[0] retorna o primeiro elemento, ou seja, o registro JSON grande que contém os dados do Twitter. Dentro desse elemento, é possível isolar facilmente um único campo. Nesse caso, o array de resultados contendo todos os registros de feed do Twitter é esperado. O operador -> na primeira linha é um canal simples que direciona o conteúdo da variável tweets para a função write() .

A saída do Jaql retornada pela primeira instrução é mostrada na segunda parte da Listagem 6. A saída é um registro de descritor de arquivo do Jaql, que inclui informações sobre os adaptadores de E/S e os formatos usados para processar essa instrução.

Talvez você esteja se perguntando por que um formato SequenceFile foi escolhido para esse exemplo. Como será visto mais adiante, o Jaql consegue ler e gravar esse tipo de dados em paralelo, explorando automaticamente esse aspecto fundamental da estrutura MapReduce. Esse paralelismo não é possível ao ler dados diretamente do serviço da web (como foi feito na Listagem 2). Além disso, para incentivar o processamento das consultas no tempo de execução, os dados foram transformados para isolar somente as informações de interesse e estruturados de modo a formar uma coleção de objetos pequenos. Nesse caso, registros JSON que representam tweets. É possível consultar essa estrutura com um grau mais alto de paralelismo em comparação aos dados de JSON originais retornados pelo Twitter, que consistiam em um array de nível superior com um único registro JSON, uma estrutura que não pode ser dividida para explorar o paralelismo. Embora essa amostra de dados seja muito pequena, as ideias fundamentais que acabaram de ser abordadas são muito importantes ao lidar com grandes quantidades de dados.

Depois que os dados são armazenados no HDFS, é possível usar a função read() do Jaql para recuperá-los, como mostra a Listagem 7.

Lista 7. Lendo um SequenceFile a partir do HDFS
tweetsHDFS = read(seq("/user/idcuser/sampleData/twitter/recentTweets.seq")); 
                
tweetsHDFS; 
                
// Sample Jaql output
[
    {
        "created_at": "Mon, 30 Apr 2012 18:42:37 +0000",
        "from_user": "SomeSampleUser",
        "from_user_id": 444455555,
        "from_user_id_str": "444455555",
        "from_user_name": "Some Sample User",
        "geo": null,
        "id": 000000000000000001,
        "id_str": "000000000000000001",
        "iso_language_code": "en",
        "metadata": {
        "result_type": "recent"
        },
        "profile_image_url": 
        "http://a0.twimg.com/profile_images/222222/TwitterPic2_normal.jpg",
        "profile_image_url_https": 
        "https://si0.twimg.com/profile_images/222222/TwitterPic2_normal.jpg",
        "source": "<a href="http://news.myUniv.edu/" rel="nofollow">MyUnivNewsApp</a>",
        "text": "RT @MyUnivNews: IBM's Watson Inventor will present 
        at a conference April 12   http://confURL.co/xrr5rBeJG",
        "to_user": null,
        "to_user_id": null,
        "to_user_id_str": null,
        "to_user_name": null
    }, 
    . . . 
    {
        "created_at": "Mon, 30 Apr 2012 17:31:13 +0000",
        "from_user": "anotheruser",
        "from_user_id": 76666993,
        "from_user_id_str": "76666993",
        "from_user_name": "Chris",
        "geo": null,
        "id": 66666536505281,
        "id_str": "66666536505281",
        "iso_language_code": "en",
        "metadata": {
        "result_type": "recent"
        },
        "profile_image_url": 
        "http://a0.twimg.com/profile_images/3331788339/Mug_Shot.jpg",
        "profile_image_url_https": 
        "https://si0.twimg.com/profile_images/3331788339/Mug_Shot.jpg",
        "source": "<a href="http://www.somesuite.com" rel="nofollow">SomeSuite</a>",
        "text": "IBM's Watson training to help diagnose and treat cancer 
        http://someURL.co/fBJNaQE6",
        "to_user": null,
        "to_user_id": null,
        "to_user_id_str": null,
        "to_user_name": null
    } 
]

Agora que os dados de interesse foram isolados e recuperados a partir do HDFS, é possível examinar outros cenários de consulta.

Recuperando diversos campos

É possível explorar a recuperação de diversos campos a partir dos dados que foram gravados no HDFS. Especificamente, suponha que você quer obter uma coleção de registros, cada um deles contendo os campos de data de criação (created_at), geografia (geo), ID do usuário do Tweeter (from_user_id_str), código do idioma (iso_language_code) e texto (text) associados aos tweets retornados. Se você está familiarizado com SQL, é possível ficar tentado a escrever algo parecido com o código mostrado na Listagem 8, que chama a expressão transform do Jaql com diversos campos. No entanto, o resultado disso será um erro.

Lista 8. Uso incorreto da expressão de transformação do Jaql para extrair diversos campos de um registro
                // Incorrect syntax for extracting multiple fields 
                tweetsHDFS -> transform $.created_at, $.geo, 
                $.from_user_id_str, $.iso_language_code, $.text;

Agora veja a forma adequada de atingir o seu objetivo, como mostra a Listagem 9.

Lista 9. Recuperando campos selecionados e os retornando como registros JSON dentro de um array
tweetsHDFS -> transform { 
              created_at: $.created_at, 
              geo: $.geo, 
              id: $.from_user_id_str, 
              iso_language_code: $.iso_language_code, 
              text: $.text };             
                
// Sample Jaql output
[
    {
        "created_at": "Mon, 30 Apr 2012 17:30:09 +0000",
        "geo": null,
        "id": "888888888",
        "iso_language_code": "en",
        "text": "#someUser: IBM\'s Watson Has An Answer 
           About The Future of Health Care | http://someURL.co/ZZ1XX via #mynews"
    },
. . . 
    {
        "created_at": "Mon, 30 Apr 2012 17:24:43 +0000",
        "geo": null,
        "id": "77777777",
        "iso_language_code": "en",
        "text": "Great news! \"RT @SomePlace: 
           Can Watson, IBM\'s Supercomputer, Cure Cancer? http://someURL.co/DDk1a \""
    }
]

Como a variável tweetsHDFS contém um array de registros JSON, use a expressão transform para acessar todos os registros contidos nesse array por meio da variável especial de cifrão. Além disso, especifique que deseja transformar cada registro de entrada em um novo registro JSON (entre chaves). Cada novo registro irá conter os cinco campos desejados e representados como um par nome/valor. Por exemplo, o primeiro campo do novo registro é created_at (um nome arbitrário) e o seu valor é derivado do campo $.created_at do array de entrada.

Exceção: ao definir o novo registro JSON a ser gerado pela expressão transform do Jaql, é possível omitir o nome do campo se quiser que o Jaql o infira a partir do nome do campo no array de entrada. Conforme mostrado anteriormente na Listagem 9, por exemplo, quatro dos cinco campos definidos para o novo registro JSON têm nomes iguais aos de seus campos correspondentes no array de entrada. Portanto, você poderia ter deixado de especificar esses nomes de campo explicitamente. A Listagem 10 mostra essa notação na forma curta.

Lista 10. Usando nomes de campo padrão ao especificar a estrutura do novo registro JSON
// short-hand version of prior query 
// Jaql will infer field names unless explicitly stated  
tweetsHDFS -> transform { 
                $.created_at, 
                $.geo, 
                id: $.from_user_id_str, 
                $.iso_language_code, 
                $.text };

Filtrando dados

Outro requisito comum nas consultas envolve a filtragem dos dados com base em critérios especificados pelo usuário. Por exemplo, imagine que deseja recuperar registros de tweets baseados em inglês. A Listagem 11 mostra uma forma simples de fazer isso.

Lista 11. Recuperando campos selecionados e filtrando dados com base em um único predicado de consulta
// Query 1:  transform data, retrieving select fields 
tweetRecords = tweetsHDFS 
            -> transform { 
            created_at: $.created_at, 
            geo: $.geo, 
            id: $.from_user_id_str, 
            iso_language_code: $.iso_language_code, 
            text: $.text };
                
// Query 2:  filter data, retraining only English records 
tweetRecords -> filter $.iso_language_code == "en"; 
                
// Sample Jaql output
[
    {
        "created_at": "Mon, 30 Apr 2012 17:30:09 +0000",
        "geo": null,
        "id": "888888888",
        "iso_language_code": "en",
        "text": "#someUser: IBM\'s Watson Has An Answer 
           About The Future of Health Care | http://someURL.co/ZZ1XX via #mynews"
    },
. . . 
    {
        "created_at": "Mon, 30 Apr 2012 17:24:43 +0000",
        "geo": null,
        "id": "77777777",
        "iso_language_code": "en",
        "text": "Great news! \"RT @SomePlace: 
           Can Watson, IBM\'s Supercomputer, Cure Cancer? http://someURL.co/DDk1a \""
    }
]

A primeira consulta é quase idêntica à consulta mostrada anteriormente na Listagem 9, com exceção de que uma variável tweetRecords é definida para conter o registro JSON que contém os campos de interesse referentes a cada tweet. A segunda consulta alimenta essa variável como entrada para a expressão filter do Jaql, que examina o campo iso_language_code procurando o valor de en, o código de idioma ISO que designa o inglês. Novamente, o cifrão é uma variável especial apresentada pela expressão filter que liga cada elemento de entrada a ela. Em seguida, campos únicos podem ser acessados facilmente usando a notação de ponto mostrada na listagem. Os registros que se qualificarem serão incluídos na saída, conforme o mostrado no final da listagem.

Se quiser filtrar os resultados da consulta com base em várias condições, simplesmente use a sintaxe AND / OR do Jaql. Por exemplo, a consulta da Listagem 12 retorna os registros de tweets baseados em inglês para os quais não se especificou nenhuma geografia. Esses registros terão um valor nulo no campo geo. Para fazer o teste referente à presença de valores nulos, o Jaql fornece as expressões isnull e not isnull .

Lista 12. Especificando diversos predicados de consulta (condições do filtro)
tweetRecords -> filter $.iso_language_code == "en" and isnull $.geo;

Classificação de dados

A classificação de dados é outro requisito comum das consultas e uma operação objetiva a ser realizada no Jaql. Imagine que você quer classificar os registros de tweets por ID do usuário em ordem crescente. A Listagem 13 mostra a sintaxe apropriada.

Lista 13. Classificando os resultados das consultas
tweetRecords -> sort by [$.id asc]

O array representado pela variável tweetRecords é fornecido como entrada para a expressão sort by do Jaql, que requer pelo menos um campo para servir de base de classificação. O campo $.id (que representa o ID do usuário) é fornecido e se especifica asc (ordem crescente). Para a ordem decrescente, é possível especificar desc.

Também é possível classificar com base em vários critérios, como mostra a Listagem 14.

Lista 14. Especificando vários critérios de classificação
// Sort by id (ascending), then geo (descending) 
tweetRecords -> sort by [$.id asc, $.geo desc];

Agregando dados

Certos aplicativos exigem que os dados sejam agrupados e que os agregados sejam calculados para todos os grupos. O Jaql suporta funções comuns de agregação, como min (mínimo), max (máximo), count e outros. Explore o exemplo simples a seguir.

Imagine que você quer contar o número de registros de tweet para cada código de idioma ISO. A Listagem 15 mostra a sintaxe apropriada.

Lista 15. Agregando dados
tweetRecords -> 
group by key = $.iso_language_code 
 into { groupingKey: key, num: count($) };
                
// Sample Jaql output 
[
    {
        "groupingKey": "de",
        "num": 1
    },
    {
        "groupingKey": "en",
        "num": 12
    },
    {
        "groupingKey": "fr",
        "num": 2
    }
]

Os registros do tweet são fornecidos pela expressão group by do Jaql. Ao fazer isso, use $.iso_language_code como critério de agrupamento e defina uma variável chamada key para se referir ao valor com base no qual você está agrupando. Embora esse exemplo agrupe com base em um único campo, o Jaql também permite agrupar pelos registros se for necessário agrupar por mais de um valor.

Além disso, é possível indicar que os resultados devem ser gravados em novos registros JSON, cada um deles formado por pares nome/valor. A groupingKey conterá o valor do código de idioma ISO encontrado nos registros, ao passo que num conterá a contagem de cada valor. A cláusula into é chamada uma vez para cada valor exclusivo de agrupamento e permite desenvolver um valor de saída para o grupo. Na expressão na cláusula into , é possível usar o nome do grupo (chave) que você forneceu para se referir ao valor de agrupamento atual, e a variável $ será um array de todos os registros que se enquadram no grupo. Como resultado, count($) fornece uma contagem de todos os registros.

A saída de amostra mostrada anteriormente na Listagem 15 contém três registros JSON incluídos no array retornado. É possível ver que um registro de tweet foi escrito em alemão (código ISO "de"), 12 foram escritos em inglês (código ISO "en") e dois foram escritos em francês (código ISO "fr").

Dividindo a saída da consulta usando a função tee

Se você está familiarizado com comandos Unix provavelmente já usou o tee para dividir a saída de um programa para dois destinos, como um monitor de terminal e um arquivo. O Jaql contém uma construção semelhante que permite dividir a saída de uma consulta com base nos resultados de chamadas de função. Um uso típico envolve gravar a saída em dois arquivos diferentes.

Como mostra a Listagem 16, a função tee do Jaql é usada com uma expressão filter para gravar dados em dois arquivos locais. Isso pode ser útil para diagnosticar ou customizar a entrada do arquivo de acordo com as necessidades de aplicativos específicos.

Lista 16. Usando a função tee do Jaql para dividir a saída da consulta em dois arquivos
tweetRecords -> tee( -> filter $.iso_language_code == "en" -> 
                        write(jsonTextFile("file:///home/hdpadmin/en.json"))
                     -> filter $.iso_language_code != "en" -> 
                        write(jsonTextFile("file:///home/hdpadmin/non-en.json"))
                   );

Nesse caso, foi adotada uma abordagem simples: gravar os registros de tweets baseados em inglês no arquivo en.json e preservar os outros registros de tweets no arquivo local non-en.json. Assim, caso queira aplicar funções de análise de texto a mensagens baseadas em inglês, você terá isolado essas mensagens em um arquivo específico.

Observe que file:/// é usado como um esquema para o URI do caminho; isso referencia o sistema de arquivos local (não o HDFS).

Dados de união

Assim como a SQL e outras linguagens de consulta, o Jaql permite unir dados de várias origens (vários arrays de JSON). A expressão union do Jaql não remove duplicatas, portanto, funciona de forma semelhante à expressão UNION ALL da SQL.

A Listagem 17 mostra um cenário simples que usa a expressão union para ler dados de dois SequenceFiles armazenados no HDFS.

Lista 17. União de dados de dois arquivos
union(read(seq('/user/idcuser/sampleData/twitter/tweet1.seq')), 
      read(seq('/user/idcuser/sampleData/twitter/tweet2.seq'))
      );

Esses arquivos foram criados a partir de dados do Twitter recuperados em momentos diferentes usando APIs baseadas em REST (consulte a Listagem 2) e gravados no HDFS usando a função write() (consulte a Listagem 6). Com os dados coletados, é simples unir esses arquivos especificando duas operações de leitura como parâmetros da expressão union .

Opcionalmente, você poderia ter gravado os resultados dessa operação de união no HDFS.

Juntando dados

Para concluir a sua introdução ao Jaql, você verá como juntar dados. Lembre-se de que a variável ibm definida anteriormente na Listagem 3 contém dados recuperados a partir de um DBMS relacional sobre funcionários da IBM cujo trabalho inclui publicar mensagens na mídia social. Imagine que você deseja juntar esses dados corporativos com tweets representados pela variável tweetRecords definida na Consulta 1 da Listagem 11. Os campos ibm.ID e tweetRecords.id atuam como chave de junção, conforme o mostrado na cláusula where na segunda linha da Listagem 18. Observe que os nomes de campo fazem distinção entre maiúsculas e minúsculas no Jaql.

Lista 18. Juntando dados extraídos de um site de mídia social com dados extraídos de um DBMS relacional
join tweetRecords, ibm
where tweetRecords.id == ibm.ID
into {
ibm.ID, ibm.NAME, ibm.TITLE, tweetRecords.text, tweetRecords.created_at
} 
-> sort by [$.ID asc];
                
// Sample output 
[
    {
        "ID": "159088234",
        "NAME": "James Smith",
        "TITLE": "Consultant",
        "text": "Great news! \"RT @OwnPrivateCloud: Can Watson, 
            IBM\'s Supercomputer, Cure Cancer? http://sampleURL.co/dgttTra \"",
        "created_at": "Mon, 30 Apr 2012 17:28:43 +0000"
    },
    {
        "ID": "370988953",
        "NAME": "John Taylor",
        "TITLE": "IT Specialist",
        "text": "http://someURL.co/45x044 Can Watson, 
            IBM\'s Supercomputer, Cure Cancer? - CIO",
        "created_at": "Mon, 30 Apr 2012 17:11:58 +0000"
    }
]

A cláusula into que começa na terceira linha da Listagem 18 define um novo registro JSON para o resultado da consulta. Nesse caso, cada registro irá conter cinco campos. Os três primeiros se baseiam em dados recuperados do DBMS relacional, ao passo que os dois restantes se baseiam nos dados de mídia social. Finalmente, você classifica a saída.


Paralelismo e Jaql

Agora que você está familiarizado com os fundamentos do Jaql, pode voltar a um tópico apresentado anteriormente: a exploração do paralelismo no Jaql por meio da estrutura MapReduce. Embora muitas tarefas de consulta possam ser divididas (executadas em paralelo) nos vários nós do seu cluster do BigInsights, certas consultas, ou, mais frequentemente, certas partes de consultas do Jaql, talvez não possam explorar o paralelismo do MapReduce. Para que o Jaql produza um plano de execução de consulta com um tipo de trabalho que possa ser dividido em várias tarefas de Map e Reduce, as duas propriedades básicas de consulta a seguir devem estar presentes.

  1. Os dados de entrada/saída da consulta têm que ser adequados para o particionamento. Os dados que residem em algum tipo de sistema de armazenamento distribuído, como HDFS, HBase ou até alguns DBMSs, normalmente são adequados. Dados lidos de um serviço da web, dados de JSON armazenados no sistema de arquivos local e dados de JSON que contêm registros de várias linhas são exemplos de dados que não são adequados.
  2. Os operadores utilizados no Jaql devem ser adequados para o particionamento, e o Jaql deve saber como paralelizá-los por meio de MapReduce. Todos os operadores de arrays grandes do Jaql preenchem esses critérios, inclusive transform, expand, filter, sort, group by, join, tee e union. No entanto, algumas chamadas de função podem não ser.

Além disso, o Jaql é adequado para processar arrays de JSON com muitos objetos pequenos. As estruturas de dados que contêm uma pequena quantidade de objetos grandes não são tão adequadas, já que um único objeto grande não pode ser "dividido" para explorar o paralelismo do MapReduce.

Talvez a melhor forma de ver quais partes de uma consulta do Jaql serão executadas em paralelo e quais serão executados serialmente é usar a instrução explain para mostrar o plano de execução da consulta. Basta prefixar qualquer consulta com explain e inspecionar a saída dos operadores mapReduce e mrAggregate, que indicam o uso de uma tarefa do MapReduce para executar a sua consulta total ou parcialmente.

Embora a explicação detalhada do recurso explain do Jaql esteja fora do escopo deste tutorial, é possível revisar brevemente um exemplo simples. Anteriormente neste artigo, a Listagem 2 definiu a variável tweets para conter os resultados da leitura de dados do Twitter a partir de um serviço da web. Posteriormente, depois que você transformou e gravou um subconjunto desses dados em um SequenceFile no HDFS, a Listagem 7 leu esse arquivo dentro da variável tweetHDFS .

Considere as duas consultas do Jaql mostradas na Listagem 19. Cada uma delas retorna os mesmos resultados, ou seja, um array de valores id_str. (O Twitter originalmente retornou esse campo como parte do array de resultados dentro de um registro JSON maior. Os dados de tweetsHDFS se baseiam em uma projeção do array de resultados. Portanto, a Consulta 2 não precisa referenciar o array de resultados.

Lista 19. Duas consultas para explicar
// Query 1:  get the "id_str" field from Web source
// and return data in as a "flat" array 
tweets -> expand $.results.id_str;
                
                
// Query 2:  get the "id_str" field from HDFS file 
// Data structure was already "flattened" when written to HDFS  
tweetsHDFS -> transform $.id_str;

Conforme o indicado anteriormente, o Jaql pode paralelizar (particionar o trabalho) dos operadores expand e transform . Portanto, o segundo critério mencionado no início desta seção vale para as duas consultas. No entanto, o primeiro critério não é. Um SequenceFile no HDFS pode ser particionado e processado usando uma tarefa de MapReduce, mas uma conexão de fluxo ao serviço da web não permite o particionamento de dados. Consequentemente, a Consulta 2 mostrada anteriormente na Listagem 19 pode ser processada por meio da várias tarefas de MapReduce porque você se deu ao trabalho de definir uma estrutura formada por muitos objetos pequenos (muitos registros JSON) para o SequenceFile. A Consulta 1, por outro lado, não pode ser paralelizada, já que seus dados são recuperados dinamicamente a partir de um serviço baseado em REST.

A análise da saída de explain permite ver os dois planos de acesso a dados diferentes dessas consultas. A Listagem 20 contém o plano de acesso a dados da Consulta 1.

Lista 20. Resultados de explain para uma consulta que não explora o paralelismo
// Explain for Query 1 
explain tweets -> expand $.results;
                
system::read(system::const({
       "location": "http://search.twitter.com/search.json?q=IBM+Watson",
       "inoptions": {
    "adapter": "com.ibm.jaql.io.stream.StreamInputAdapter",
    "format": "com.ibm.jaql.io.stream.converter.JsonTextInputStream",
    "asArray": false
}
    })) -> expand each $ ( ($).("results") )
;

Como é possível ver, o plano não tem nenhuma indicação de um operador mapReduce ou mrAggregate. Isso significa que a consulta lerá e processará os dados dentro de uma única Java virtual machine (JVM).

Por outro lado, o resultado de explain referente à Consulta 2 mostrado na Listagem 21 indica que os dados são lidos e processados como uma tarefa de MapReduce, como é possível ver pela presença do operador mapReduce no início da saída de explain.

Lista 21. Resultados de explain para uma consulta que explora o paralelismo
// Explain for Query 2 
explain tweetsHDFS -> transform $.id_str;
                
(
    $fd_0 = system::mapReduce({ ("input"):(system::const({
       "location": "/user/idcuser/sampleData/twitter/recentTweets.seq",
       "inoptions": {
    "adapter": "com.ibm.jaql.io.hadoop.DefaultHadoopInputAdapter",
    "format": "org.apache.hadoop.mapred.SequenceFileInputFormat",
    "configurator": "com.ibm.jaql.io.hadoop.FileInputConfigurator"
},
        "outoptions": {
    "adapter": "com.ibm.jaql.io.hadoop.DefaultHadoopOutputAdapter",
    "format": "org.apache.hadoop.mapred.SequenceFileOutputFormat",
    "configurator": "com.ibm.jaql.io.hadoop.FileOutputConfigurator"
}
    })), ("map"):(fn(schema [ * ] $mapIn) ($mapIn
-> transform each $ (($).("id_str"))
-> transform each $fv ([null, $fv]))), ("schema"):(system::const({
        "key": schema null,
        "value": schema any
    })), ("output"):(system::HadoopTemp()) }),
    system::read($fd_0)
)
;

Você verá que o operador transform do Jaql é enviado por push para as tarefas de mapa, e cada Mapper realiza a operação necessária em paralelo nessa partição dos dados. Essa consulta gerou uma tarefa somente de mapa, portanto, nenhuma tarefa de redução é incluída na saída de explain.


Usando a saída de consulta do Jaql com o BigSheets

Até agora, você armazenou a saída das suas consultas como um SequenceFile no HDFS. Esses arquivos geralmente são práticos para os programadores, mas provavelmente os analistas de negócios e outros funcionários não técnicos consideram que outros tipos de arquivo são mais fáceis de trabalhar.

Imagine que você quer que a saída de uma consulta do Jaql (ou mais) seja armazenada no HDFS em um formato que possa ser exibido facilmente no BigSheets, uma ferramenta com estilo de planilha fornecida com o BigInsights. Se você não está familiarizado com o BigSheets, consulte a seção Recursos para obter os links para um artigo e vários vídeos sobre essa ferramenta para analistas de negócios. Já que o BigInsights inclui vários adaptadores de E/S diferentes do Jaql, é fácil ajustar um dos exemplos de consulta anteriores para armazenar a saída como um arquivo separado por caracteres (arquivo .del), um formato que o BigSheets pode consumir facilmente. E, caso você esteja se perguntando, esse trabalho de E/S é algo que o Jaql pode paralelizar.

A Listagem 22 mostra como é possível gravar os resultados de uma consulta como um arquivo delimitado no HDFS. Observe que há um esquema especificado para o arquivo de saída, que controla a ordem na qual os campos especificados aparecerão nos registros dentro do arquivo.

Lista 22. Manipulando e armazenando dados como um arquivo delimitado
// the tweets variable was defined earlier, in Listing 2 
sheetsData = tweets -> expand $.results
           -> transform { created_at: $.created_at,
                    geo: $.geo,
                    id: $.from_user_id_str,
                    iso_language_code: $.iso_language_code,
                    text: $.text };
                
// write that data as a delimited file in the distributed file system
sheetsData -> write(del('/user/idcuser/sampleData/twitter/tweetRecords.del', 
                schema = schema {created_at, geo, id, iso_language_code, text}));

Depois de gravar o arquivo no HDFS, é possível ativar o console da web do BigInsights e acessar a guia Files para localizar a saída, como mostra a Figura 2.

Figura 2. Definindo uma coleção do BigSheets com base na saída do Jaql gravada no HDFS
Definindo uma coleção do BigSheets com base na saída do Jaql gravada no HDFS

Siga o processo padrão para definir uma coleção do BigSheets para esses dados. Na área direita da janela da Figura 2, altere a configuração de exibição do arquivo de Text para Sheetse, em seguida, reconfigure o tipo de leitor para valores separados por vírgula sem cabeçalho. Para ver detalhes sobre a criação e o trabalho com coleções do BigSheets, consulte o artigo mencionado na seção Recursos .

Como comentário à parte, você também poderia gravar o conteúdo da variável tweetRecords (definida anteriormente na Listagem 11) no HDFS como um arquivo delimitado, como mostra a Listagem 23.

Lista 23. Gravando dados representados por tweetRecords como um arquivo delimitado
// write records as a delimited file in the distributed file system
tweetRecords -> write(del('/user/idcuser/sampleData/twitter/tweetRecords', 
schema = schema {created_at, geo, id, iso_language_code, text}));

Essa ação produzirá um diretório, em vez de um único arquivo, no HDFS. Para ver o conteúdo no BigSheets, você criaria uma nova coleção sobre o diretório, em vez de uma coleção dos arquivos de saída contidos no diretório.


Conclusão

Este artigo apresentou a você o Jaql, uma linguagem de script e consulta para trabalhar com Big Data. Especificamente, mostrou como é possível usar o Jaql com o InfoSphere BigInsights para ler, gravar, filtrar e manipular dados estruturados e de mídia social usando uma variedade de expressões e funções fornecidas pela linguagem. Este artigo também mostrou como o Jaql explora o processamento paralelo inerente à estrutura MapReduce e ilustrou como se pode usar o recurso explain do Jaql para determinar o caminho de acesso aos dados que o BigInsights executou para a sua consulta. Finalmente, você aprendeu uma forma de formatar e armazenar os resultados das consultas do Jaql em um formato que é consumido facilmente pelo BigSheets, uma ferramenta no estilo de planilha para analistas de negócios que é fornecida com o BigInsights.

Certamente, este artigo introdutório não tem condições de explicar tudo sobre o Jaql. Há mais coisas a aprender. Por exemplo, o Jaql suporta funções e módulos definidos pelo usuário, bem como muitas construções de SQL. Também suporta a analítica de texto no BigInsights, para permitir que os programadores executem extratores de texto fornecidos pela IBM e extratores de texto customizados. Para obter mais detalhes sobre o Jaql, consulte a seção Recursos .

Agradecimentos

Agradecemos às pessoas que contribuíram para este artigo ou o revisaram. Essas pessoas são, em ordem alfabética: Rafael Coss, Vuk Ercegovac, Scott Gray, Manoj Kumar e Nicolas Morales.

Recursos

Aprender

Obter produtos e tecnologias

  • Crie seu próximo projeto de desenvolvimento com a Versão de teste do software IBM, disponível para download diretamente do developerWorks.
  • Avalie os produtos IBM da maneira que for melhor para você: faça download da versão de teste de um produto, avalie um produto online, use-o em um ambiente de nuvem ou passe algumas horas no Ambiente de Simulação da SOA aprendendo a implementar Arquitetura Orientada a Serviços de modo eficiente.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Information Management
ArticleID=831366
ArticleTitle=Use o InfoSphere BigInsights para Consultar Mídias Sociais e Dados Estruturados
publish-date=08242012