Base de Dados para Treinamento

Para escrever o Pentaho na Prática eu construí, do zero, uma base de dados – a Beltrano S/A. Ela está disponível na forma de um backup Postgres, com licença que permite até mesmo o uso comercial. Ou seja, se você quiser montar um curso, ou um produto, embutindo a Beltrano S/A, pode.


A única coisa que eu peço em troca é ser informado no que ela está sendo usada. Só. E mesmo assim, se não quiser não precisa me falar nada. Liberdade total. ;-)


A julgar pelo feedback de quem pediu para usar, eu diria que, como material de ensino, a base é interessante. Por outro lado, como tecnologia ela é bem pouco prática, na minha opinião.

Começa que, para usar, é preciso instalar o Postgres. Depois, precisa criar um banco, baixar o backup, restaurá-lo etc. Daí, se você alterar o conteúdo e quiser resetar o banco para o estado inicial, é preciso dropar a base e recriá-la. E se quiser customizar, precisa extrair umbackup no final e repetir o passo-a-passo de configuração em todas as máquinas de alunos.

É um trabalho chato mesmo para quem sabe mexer no Postgres. Para quem tem pouca familiaridade, é um porre.

Nem todo mundo é fluente em Postgres, e nem sempre dá para instalá-lo nas máquinas. Ou até dá, mas pode rolar conflito de porta, restrições de administração, blá blá blá… Eu ministrei umas vinte turmas de [BI com Pentaho][bicp4lin_bitly], e em todas elas sempre houve ao menos uma pessoa/máquina com problema sério na preparação do banco.

Bom, Bonito e Barato

Existe um servidor de banco de dados chamado HSQLDB que é 100% Java e que não precisa ser instalado. Basta baixar o arquivo do programa, rodá-lo com Java e voilà, tudo em riba!

Como se não bastasse ser Software Livre e 100% Java (ou seja, 100% portável – roda em qualquer plataforma, mesmo!), ainda tem uma interface gráfica a lá pgAdmin III, que pode ser usada para explorar os bancos e executar comandos SQL.

Mas tem uma coisa mais legal ainda: os bancos são construídos, por default, em memória. Quando o servidor é baixado, ele grava tudo que estava em memória em arquivos texto planos, no diretório que especificarmos. Isso, mais o fato de tomar muitas de suas configurações de servidor da linha de comando, nos dá muitas vantagens:

  • Qualquer modificação que é feita nos dados pode ser mantida e transferida para outras máquinas, simplificando o processo de customização para cada uso;
  • Se quiser voltar ao estado original, basta apagar o banco atual e descompactar o banco inicial mais uma vez. Estou falando do Beltrano S/A, mas pode ser feito para qualquer outro banco que você criar: basta guardar uma cópia à parte do seu banco;
  • Ele não mantém arquivos escondidos. Apagou, desinstalou;
  • A porta é configurada na chamada que sobe o servidor. Deu conflito? Baixe o banco, mude a porta e suba novamente;
  • Como podemos rodar um programa Java quantas vezes quisermos, podemos montar um conjunto de vários servidores, cada qual com sua porta e seu banco;
  • Um mesmo servidor, aliás, pode manter vários bancos;
  • É um programa pequeno: o pacote inteiro não chega a 5MB;
  • Mesmo tendo uma “pegada” muito pequena, ele não deixa nada a dever a bancos maiores, em termos de funcionalidades, e aguenta um bom volume de dados (basicamente limitado pela RAM da máquina;)
  • Você pode embuti-lo em outros programas, afinal é um projeto livre, em Java;
  • Você pode carregar data marts nele, e dar a capacidade de processamento de dados in memory a qualquer ferramentas de análises de dados que se conecte a bancos de dados via JDBC, como o Pentaho. Evidentemente não é a mesma coisa que um engine otimizado, como o que acompanha o QlikView, mas é mais rápido que disco.

E o HSQLDB ainda oferece uma boa gama de comandos e recursos, como índices, integridade relacional, muitos tipos de dados, várias funções nativas etc. etc. etc. Não fica a dever para outros bancos, mesmo.

Quem me conhece deve estar esperando a pegadinha, que sempre vem depois que eu desenho uma cena linda, toda rósea e luminosa. ;-) Bom, desta vez não tem: é tudo róseo e lindo, mesmo! No restante do post você verá um pouco sobre o HSQLDB (como baixar e subir um banco) e como instalar o mesmo conteúdo do banco Beltrano S/A oferecido em PostgreSQL.

Introdução ao HSQLDB

Como a promessa deste post é oferecer uma base de treinamento pronta e fácil de usar, eu vou cortar direto para a perseguição1 e ensinar o bê-a-bá do agá-esse-kê-ele-debê: de onde fazer o download, como subir o servidor, criar novos bancos, acessá-lo e depois baixá-lo.

O site do HSQLDB é o http://hsqldb.org, onde você pode estudar toda documentação e ler os guias de uso. Como é um projeto voltado principalmente para programadores (é um banco embutível, afinal de contas), ele abusa da linguagem técnica, tanto SQL quanto Java, e pode ser um pouco árido para o usuário menos proficiente nesses assuntos.

O pacote do servidor HSQLDB pode ser baixado diretamente do SourceForge, neste link, e o pacote do Beltrano S/A pré-configurado pode ser baixado daqui. O restante desta seção usa o conteúdo desse pacote, não do servidor original – muito técnico, lembram-se?

O zip do Beltrano OLTP/HSQLDB traz os arquivos do servidor e mais dois scripts, cada um dos quais em duas versões: Linux (.sh) e Windows (.bat.) Um dos scripts sobe o servidor e outro baixa-o. Os diretórios são ./data, onde fica o conteúdo do banco propriamente dito, e ./lib, onde está o servidor.

Subindo e Baixando o HSQLDB

Basta rodar o script start-hsqldb.sh/bat que o HSQLDB subirá com o banco desejado – Beltrano S/A neste caso. Para rodar esse script, abra um terminal (Windows: prompt do DOS) e mude para o diretório recém-criado. Daí comande ./start-hsqldb.sh (Linux) ou start-hsqldb.bat (Windows.) Em poucos segundos o banco estará no ar.

Eis as mensagens do HSQLDB subindo em um Ubuntu:

ubuntu:beltrano_oltp_hsqldb$ ./beltrano_oltp_hsqldb
classpath is :./lib/hsqldb.jar
[Server@5cd73256]: [Thread[main,5,main]]: checkRunning(false) entered
[Server@5cd73256]: [Thread[main,5,main]]: checkRunning(false) exited
[Server@5cd73256]: Startup sequence initiated from main() method
[Server@5cd73256]: Could not load properties from file
[Server@5cd73256]: Using cli/default properties only
[Server@5cd73256]: Initiating startup sequence...
[Server@5cd73256]: Server socket opened successfully in 4 ms.
[Server@5cd73256]: Database [index=0, id=0, db=file:./data/beltrano10k, alias=beltrano_oltp] opened successfully in 1430 ms.
[Server@5cd73256]: Startup sequence completed in 1435 ms.
[Server@5cd73256]: 2016-11-24 10:37:47.379 HSQLDB server 2.3.4 is online on port 9001
[Server@5cd73256]: To close normally, connect and execute SHUTDOWN SQL
[Server@5cd73256]: From command line, use [Ctrl]+[C] to abort abruptly

Eis o conteúdo da versão Bash do script:

#!/bin/sh
### =================== ###
##  HSQLDB Start Script  ##
### =================== ###

DIR_REL=`dirname $0`
cd $DIR_REL
DIR=`pwd`
cd -

#---------------------------------#
# dynamically build the classpath #
#---------------------------------#
THE_CLASSPATH=
for i in `ls $DIR_REL/lib/hsqldb*.jar`
do
THE_CLASSPATH=${THE_CLASSPATH}:${i}
done
echo "classpath is $THE_CLASSPATH"

java -cp $THE_CLASSPATH org.hsqldb.Server
-database.0 $DIR_REL/data/beltrano
-dbname.0 beltrano_oltp -port 9001

O último comando do script acima deve estar em uma única linha.

Uma vez no ar, você não pode simplesmente apertar CTRL+C para interrompê-lo. Isso pode corromper os arquivos, sem contar que não vai salvar o que estiver em memória. Para encerrar um banco é preciso rodar o script stop-hsqldb.sh/.bat. Note que talvez seja preciso abrir outro terminal. O script de encerramento é o seguinte:

#!/bin/sh
### =================== ###
##  HSQLDB Stop Script  ##
### =================== ###

DIR_REL=`dirname $0`
cd $DIR_REL

java -jar $DIR_REL/lib/sqltool.jar
--inlineRc=url=jdbc:hsqldb:hsql://localhost:9001/nome_do_banco,user=SA,password=""
--sql="SHUTDOWN;"

De novo: linhas maiores foram separadas em várias para facilitar a leitura, mas sempre devem formar uma única linha, sem quebras.

A diferença deste script para o de inicialização é que você não precisa informar o(s) nome(s) do(s) banco(s): ao receber o comando para se desligar, o HSQLDB encerra todos que estiverem abertos. Apenas não se esqueça de conferir as portas: o comando de shutdown precisa ser enviado para a porta certa, caso contrário, óbvio, nada acontecerá.

Acessando o Servidor

O HSQLDB é um servidor de banco de dados como outro qualquer. Ele pode ser acessado por qualquer aplicação que use o padrão JDBC. O driver JDBC dele, aliás, é o próprio servidor. No pacote do Beltrano S/A o servidor/driver é o arquivo hsqldb.jar, que fica dentro da pasta ./lib. Basta passar esse arquivo para o programa que vai se conectar ao servidor HSQLDB e usar a string de conexão abaixo:

jdbc:hsqldb:hsql://:/; ~~~

`<PARAMETROS>` é qualquer configuração que precise ser passada para o servidor. Lembre-se de remover o **;** entre a URL e os parâmetros caso não haja nenhum.

Digamos que você queira usar o PDI (Kettle) para acessar esse servidor. Uma conexão com o HSQLDB é totalmente padrão: basta selecionar Hypersonic (seu antigo nome) na lista e entrar os dados de conexão:

<a href="https://geekbi.files.wordpress.com/2016/11/161123_basededadosparatreinamento_004.png"><img class="size-full wp-image-1550" src="https://geekbi.files.wordpress.com/2016/11/161123_basededadosparatreinamento_004.png" alt="Parâmetros de conexão Pentaho." width="608" height="500" /></a> Parâmetros de conexão Pentaho.

Porém, é importante setar um parâmetro para evitar problemas com &quot;conjuntos vazios&quot; (conexões que se abre e fecham sem gravar nada, acho.) Na janela de conexões do *Spoon*, acesse a seção *Options* e entre o parâmetro `allow_empty_batch = true`:

<a href="https://geekbi.files.wordpress.com/2016/11/161123_basededadosparatreinamento_003.png"><img class="size-large wp-image-1551" src="https://geekbi.files.wordpress.com/2016/11/161123_basededadosparatreinamento_003.png?w=720" alt="Onde adicionar o parâmetro para evitar problemas com INSERTs vazios." width="720" height="278" /></a> Onde adicionar o parâmetro para evitar problemas com INSERTs vazios.

A string de conexão ficaria:

jdbc:hsqldb:hsql://localhost:9001/beltrano_oltp;allow_empty_batch=true

<br />Aproveitando, se você precisa construir uma conexão [JNDI][JNDI_bitly], o formato é esse:

BELTRANO_OLTP/type=javax.sql.DataSource
BELTRANO_OLTP/driver=org.hsqldb.jdbcDriver
BELTRANO_OLTP/url=jdbc:hsqldb:hsql://localhost:9001/beltrano_oltp
BELTRANO_OLTP/user=sa
BELTRANO_OLTP/password=

<br />Lembre-se de ajustar os parâmetros para o seu caso!

### Criar Novos Bancos ###

Pronto, agora você possui um servidor de banco de dados portátil, versátil, apto a um monte de usos educacionais e profissionais. Por exemplo, você pode criar um Data Mart para servir relatórios.

> ---
>
> Francamente, eu não consegui entender a documentação. Não sei dizer se dá para criar um banco subindo um servidor "vazio" e fazendo um `CREATE DB` ou coisa do gênero. Logo, eu vou contar aqui o que eu sei que funciona, mas não é necessariamente a única forma de fazê-lo - eu só não sei de outras. ;-)
>
> ---

Observe a linha de comando Java do script de inicialização:

java -cp $THE_CLASSPATH org.hsqldb.Server
-database.0 $DIR_REL/data/beltrano
-dbname.0 beltrano_oltp -port 9001

<br />É ali que definimos que bancos o servidor vai oferecer, a partir de que diretório, em que porta etc. Logo, para criar um novo banco basta adicionar, a essa linha, um par de parâmetros:

* Diretório do banco e nome dos arquivos: `$DIR_REL/data/NOME`
* Número e nome do banco de dados: `-dbname.X NOME`

Você pode adicionar um novo banco ou remover o antigo antes de criar o novo, apagando os arquivos `$DIR_REL/data/NOME`.

Para subir mais de um banco no mesmo servidor, inclua um novo conjunto de parâmetros. Por exemplo, para termos dois bancos, chamados *nome_do_banco* e *banco_de_dados*, a linha de comando deve ser:

java -cp $THE_CLASSPATH org.hsqldb.Server
-database.0 $DIR_REL/data/nomequalquer1 -dbname.0 nome_do_banco
-database.1 $DIR_REL/data/nomequalquer2 -dbname.1 banco_de_dados
-port 9001

<br />> *Atenção*: o comando acima deve compor uma única linha.

E, claro que você já deve ter sacado, para alterar a porta na qual o banco vai responder simplesmente mude o número que vem depois do parâmetro `-port`.

### Interface Gráfica ###

Em 17/1/2013 eu postei um artigo mostrando como abrir uma interface gráfica ("mais ou menos") para um servidor HSQLDB: [Interface para o HSQLDB][inthsqldb_bitly]. Vamos relembrar os pontos importantes:

* Abra um terminal (DOS prompt no Windows)
* Mude para o diretório do *HSQLDB*;
* Comande:
java -cp hsqldb.jar org.hsqldb.util.DatabaseManagerSwing --noexit

* Preencha os campos da janela Connect com os seguintes dados:

Setting name: Beltrano OLTP
URL: jdbc:hsqldb:hsql://localhost:9001/beltrano_oltp
User: sa
Senha:
~~~

A figura abaixo mostra um exemplo. Note que ela se conecta a outro banco, e por isso os parâmetros são diferentes – ela foi puxada do outro post.

Exemplo de como criar uma nova conexão.
Exemplo de como criar uma nova conexão.

Quando você conseguir se conectar, poderá explorar o banco à vontade:

Conectado ao servidor.
Conectado ao servidor.

HSQLDB & Pentaho

Se você costuma usar o Pentaho, especialmente o servidor, vale a pena notar que esse é o banco que o Pentaho BA Server usa em sua instalação pré-configurada. Se você tiver curiosidade, tudo que foi descrito aqui pode ser verificado no diretório ./biserver-ce/data, se você souber a quê estou me referindo.

Conclusão

Eu já havia visto MySQL portátil, que é uma boa solução também. O único inconveniente era o fato de precisar de binários diferentes para cada arquitetura (Linux, Windows, Intel, ARM etc.) O HSQLDB supera essa limitação e é, de fato, um servidor de bancos de dados relacionais de arquitetura “universal”. Claro que não possui a mesma robustez de um servidor como Oracle ou PostgreSQL, mas resolve muito bem uma série de necessidades.

Não sei porque eu demorei tanto a perceber isso… ;-)

Não deixe de entrar em contato por meios dos comentários se tiver alguma dúvida, ou encontrar algum bug.

Até a próxima! :-)


  1. Cut to the chase é uma coisa que dizem em Inglês quando não estão a fim de ouvir a história inteira. Aqui usamos mais “vá direto ao assunto”. E porque eu usei a expressão estrangeira? Oras, para poder dizer que GeekBI é cultura, claro! Kkkk…. 
Anúncios

O Fim do BigData

Em 20/10/2016 eu tive a honra e o privilégio de falar como keynote speaker no TechnoTalk de BI, BigData e Data Science da PUC do Rio Grande do Sul. Esse é um evento que ocorre com frequência, organizado pelo insuperável Jorge Audy, Agile Jedi. Já foram mais de 40 eventos, e contando!

TechnoTalk BI, BigData & DataMining.
TechnoTalk BI, BigData & DataMining.

Desta feita o Jorge havia convidado luminares de Data Mining, de BigData e eu, vosso modesto (ha-ha) escriba. Antes de mim falaram Sérgio Blum e João Gutheil, e depois falou o Irio Musskopf. Vou apresentá-los a vocês e contextualizar a discussão que vinha sendo feita e logo depois eu coloco o ponto que eu levantei no debate.

Casa cheia!
Casa cheia!

Sérgio Adriano Blum

Instrutor, gestor de projetos e consultor em Tecnologia da Informação pela White Cube, ele apresentou um painel com opções tecnológicas, ferramentas, cases e cenários do mundo BigData/Data Mining. Sigam este link para o post do Jorge, onde vocês podem baixar o material que ele disponibilizou em PPT. Você também pode entrar em contato com o Sérgio por meio de sua página LinkedIn

Um apanhado geral das tecnologias associadas a BigData.
Um apanhado geral das tecnologias associadas a BigData.

João Gutheil

O João é um conhecido meu de longa data – já batemos papo desde o começo de 2015. A apresentação do Gutheil ligou BigData com Data Mining, detalhando abordagens, valor entregue em diferentes áreas e segmentos de mercado, ferramentas e plataformas, fechando com cenários para futuro próximo.

Vale destacar que ele é um dos vice-coordenadores do Grupo de Usuários de BI (GUBI) da SUCESU-RS. Ou seja, o cara não é fraco, não.

Minha fala foi logo depois da dele, e eu usei o que ele explicou como ponto de partida. Mas segure aí – vamos terminar os convidades e eu já volto.

Irio Musskopf

O Irio é uma daquelas pessoas que tem a rara oportunidade de fazer algo de concreto e impactante para seu país. Ele falou sobre o desafio do uso de Machine Learning na Operação Serenata de Amor, que usa mineração de dados para mapear e destacar anomalias nas prestações de contas de políticos. Para custear esse projeto foi aberto uma conta na Catarse – não deixe de conhecer, é impressionante.

Usando Data Mining e Robôs para pegar malfeitos!
Usando Data Mining e Robôs para pegar malfeitos!

A CodeLand é uma empresa de desenvolvimento web ágil, especializada na liberação de novos negócios digitais.

Explodindo o BigData e Mostrando o Creeper!

Bom, quando eu entrei o Irio seria o próximo, e o João Gutheil tinha acabado de mostrar como BigData e Data Mining poderiam ser usados para resolver problemas reais, concretos, de empresas.

Eu falei sobre minha apresentação do dia anterior, na FATEC, quando eu fiz justamente uma introdução ao assunto. Comentei, então, que na minha opinião BigData é a mesma coisa que Hadoop e que é uma tecnologia útil para resolver problemas com um volume burral de dados – um volume que não cabe dentro de uma só máquina.

Eu coloquei minha primeira pergunta: onde está a maior parte dos dados que giram pelas empresas no Brasil?

Sabemos que a maior parte dos empregos, no Brasil, estão em empresas de médio e pequeno porte, e até menores. Será que o volume de dados tratado por essas empresas também se distribui segundo essa regra? Intuitivamente eu suspeito que não. Eu desconfio que a maior parte das empresas no Brasil recolhem apenas uma pequena parcela dos dados transacionados no país.

Daí eu comecei a levantar outros pontos, que há coisa de um ano começaram a despertar minha curiosidade:

  • Certos usos dos dados não se dão bem com o modelo de operação em lote (batch) do Hadoop. Cubos OLAP são um caso, relatórios são outro. Até porque uma coisa é coletar um volume monstruoso de dados, e outra é usar parte desse volume como fonte para um cubo;
  • Um volume muito grande de dados pode ser tratado usando-se algumas outras tecnologias, como por exemplo clusters de bancos de dados relacionais, e até mesmo clusters de bancos de dados colunares. Esse tipo de tecnologia cabe na descrição de “BigData” mas ainda não é Hadoop, e se presta a coisas como, de novo, cubos OLAP, que são um ponto fraco do Hadoop ainda;
  • Por fim, o volume de dados que justifica a adoção de Hadoop é realmente uma coisa fora-do-comum. Quantas empresas existem que lidam, que captam um volume de dados deste porte?
  • Mais ainda: das empresas que coletam um volume gargantuesco de dados crús, quantas possuem problemas que requerem uma parcela tão grande desses dados que esse subconjunto seja, por si sói, um problema de BigData?

Vocês hão de concordar comigo – como de fato concordaram na hora – que não é a maioria das empresas que possuem um volume de dados que sirvam para alguma coisa e que estejam na casa do Hadoop.

Minha intenção, eu expliquei, era conseguir deles a concordância para o seguinte ponto: “não é toda empresa que precisa usar Hadoop”. Eles concordaram, já que eu havia colocado uma dúvida razoável quanto à tecnologia necessária para o tratamento de dados na maior parte das empresas – se a maior parte de empresas de um país são pequenas e médias, e elas lidam com volumes de dados que dispensam Hadoop, então não é a maior parte de empresas que precisa de Hadoop. Simples e razoável, não?

Neste momento pedi ao Jorge que colocasse esse e-mail para a platéia:

Como resolver o problema de Hadoop dos seus usuários...
Como resolver o problema de Hadoop dos seus usuários…

Notaram como ele 1) presume que você tinha um problema de BigData que foi resolvido e 2) assume que ele não deu totalmente certo, porque ainda existe gente reclamando que não está vendo o que queria? Esse “now what?” é bem chatinho! Como assim, e agora o quê? Oras, de onde ele tirou a associação entre usuários finais e Hadoop? Quem disse que Hadoop resolveria 100% dos problemas de BI de uma empresa?

É muito chute em tão pouco espaço.

Outro ponto: contei-lhes que na apresentação da FATEC eu tive muitos espectadores de cursos hardcore de TI, como Análise de Sistemas, e Hardware. Mas eu tive a presença de vários alunos de Secretariado!

Me digam, pedi a eles, não é estranho que um curso tão “humanas” coloque no espírito do aluno inquietude o bastante para ele se arriscar em uma palestra técnica sobre Hadoop/BigData?

Mais: a lotação foi muito maior que a sala comportava, e era uma sala quase do tamanho da do TechnoTaks. Já não tinha mais espaço nem para sentar-se no chão… do corredor!! Era muita gente querendo ouvir sobre um treco que, ao cabo e ao fim, tem um uso muito restrito.

Tem uso mais restrito que Data Mining, aliás. Quase toda empresa pode se beneficiar de Data Mining. Mas poucas têm uso real para Hadoop, BigData e outros quejandos deste porte!

Vestido para detonar! Kkkkk...
Vestido para detonar! Kkkkk…

Eu participei do TT remotamente. No plano original eu estaria em um Hangout com a turma em Porto Alegre, e poderia ser visto. Por isso, considerando-se o que eu estava tramando soltar, vesti-me a caráter: com uma camiseta de Minecraft. Claro, pois se eu pretendia detonar boa parte do nosso senso-comum, nada tinha mais significado que me vestir de Creeper.

“Ora”, falei, me encaminhando para o fechamento:


“Se existe tanta propaganda sobre BigData/Hadoop, a ponto de mobilizar muita gente, e de áreas pouco relacionadas; se o assunto sempre vai estar restrito a um conjunto pequeno de empresas, com um subconjunto ainda menor de problemas aplacáveis com BigData/Hadoop, então essa exposição toda não passa de hype, de propaganda, de vapor. E se for isso mesmo, não há como sustentar o atual ritmo de destaque na mídia.”


Logo, na minha opinião,


O BigData vai sumir. Não vai demorar muito e tudo isso sobre o qual falamos não será mais um assunto tão quente, e essas tecnologias estarão de volta ao nicho de Data Mining ao qual pertencem.


Conclusão

Acabou, era só isso. Frustante? Pouco?

Eu queria ter estado lá, porque pelo pouco que eu percebi, remotamente, tinha gente louca de vontade para falar. Soube que algumas cabeças balançavam afirmativamente, outras meneavam e algumas sacudiam-se.

Só para dar um grau, eis um comentário que eu recebi no dia seguinte:


Quando começaste a falar, pensei: “o que esse maluco está dizendo?”, mas conforme foste expondo teus argumentos, vi que concordo contigo. Atualmente eu trabalho na Procergs, onde está se tentando utilizar sistemas de Big Data para análise e esse, sim, é um caso atipico, de governo, onde se processa notas fiscais de vários estados. Para se ter ideia, todas as notas fiscais são armazenadas e processadas em banco relacional SQL Server e possuem um volume de Terabytes de dados, mas que ainda assim a tecnologia que está no mercado há anos, dá conta. Parabéns pela iniciativa, conseguiste passar a mensagem! E obrigado, vou aproveitar o material. Abraço, Rodrigo Batista


E você, o que acha? Pirei de vez na batatinha? Concorda comigo? ;-)

Até a próxima! :-)

BigData

(Este post deveria ter sido publicado em 19/10/16, no dia seguinte ao evento. Não deu para completá-lo no dia, e para não ficar sem nada saiu apenas os links para download. Em todo caso, as referências a datas serão mantidas. Amanhã o blog volta ao ritmo normal.)

O conjunto das FATECs de São Paulo, capital, faz um congresso de tecnologia anual. Nesta semana está ocorrendo a décima oitava edição do evento, ao qual eu fui convidado para palestrar. A coordenação do evento me deixou livre para propor o tema e acabamos ficando com BigData. A apresentação foi ontem, 18/10/16, às 10H00min, com boa presença dos alunos e até mesmo de professores (!!). Conforme prometido a todos eles, eis aqui os links para download dos slides e notas, ambos em PDF:

Você pode clicar nestes links para download direto ou, se estiver lendo em papel ou outro meio não-digital, basta copiar os bit.lys no seu navegador. Ambos arquivos estão hospedados em uma conta [DropBox][dropbox_bitly] e, por causa disso, pode ser que apareça uma tela requisitando seu login para fazer o download. Não caia nessa! Não é preciso fazer login para baixar os arquivos: examine a tela com atenção que você vai acabar descobrindo algum texto do tipo “não obrigado, leve-me ao download”. O DropBox usa qualquer opoturnidade para ampliar sua base e por isso ele fica com essas “pegadinhas”.

O post de hoje é um resumo da apresentação. Bom proveito!

De Onde Veio?

Quando a Profa. Célia me convidou para participar do fórum ela me deixou à vontade para escolher o tema. Uau, que responsa…

Como a FATEC é uma escola técnica, de tecnologia, e voltada para o mercado profissional, eu propus apresentar um pouco sobre BigData, que tem sido um assunto “quente”. Acredito que uma palestra sobre esse tema possa abrir horizontes para vocês, alunos.

Vocês podem encontrar, pela web, toneladas de vídeos, livros e textos explicando o que é BigData, como montar uma fazenda Hadoop, porque Storm é o máximo e que Social Analytics é o bicho.

De que valeria um profissional do ramo vir até aqui e alugá-los por sessenta minutos para ler powerpoint e repetir o que existe por aí? Vocês não precisam de ninguém para se virar sozinhos, não é mesmo?

Minha meta, hoje, é dar a vocês uma visão calibrada do quê, de fato, essa tecnologia significa para o mercado de TI, o que ela pode fazer e para onde eu, Fábio, acredito que esse barco vai.

Com isso eu espero dar a vocês uma vantagem em sua vida profissional, em sua busca por emprego, que – todo mundo está careca de saber – não está fácil para ninguém, certo? ;-)


Notem que, exceto pela minha certificação Pentaho, eu não tenho nenhum diploma de BI ou pós-graduação em DW nem nada do gênero. O que eu vou contar aqui eu aprendi na lida diária, no contato com problemas e soluções que afligem toda empresa moderna.


Eu vou mostrar os conceitos do Hadoop em alto nível, sem entrar nos detalhes técnicos, e daí explorar as possibilidades que surgiram, que promessas estão sendo feitas e o quê é besteira nisso tudo.

O Céu é o Limite

Todo computador funciona da mesma forma: lê dados de algum lugar, realiza alguma operação e manda o resultado para algum outro lugar.

Computador conceitual.
Computador conceitual.

Um computador nada mais é que um circuito eletrônico. Aliás, era mecânico, daí a a válvula foi inventada e deu origem ao computador eletrônico. Mais tarde ela foi substituída por transístores, que foram combinados em circuitos integrados (CI), que começaram grandes, com poucos componentes. Conforme a eletrônica se sofisticou, a quantidade de transístores por CI aumentou, elevando a velocidade de processamento.

Exemplo de circuito integrado: o famoso 555.
Exemplo de circuito integrado: o famoso 555.

Essa tendência poderia ir adiante para sempre, se não fosse um porém: a Física, a própria Natureza, interpõe certos limites.

A resistividade de um condutor aumenta conforme sua secção diminui. Logo, com circuitos integrados na casa dos milhões de transístores em menos de um centímetro quadrado, os circuitos ficam muito pequenos, o que faz com a corrente através desses circuitos gere cada vez mais calor. Para piorar, o aquecimento em si também afeta a condutividade, “somando agressão à injúria”1. No final das contas, a redução de escala é barrada por um limite prático.

E mesmo que o problema de condutividade seja resolvido usando, digamos, supercondutores, efeitos quânticos limitam o tamanho dos transístores.

Se mesmo assim conseguíssemos superar essa barreira, lá no fim acabaremos trabalhando com átomos individuais, e não dá para ficar menor que um átomo. Dá para usar átomos menores, claro, mas trocar o material do chip nunca vai remover essa barreira, vai apenas empurrá-la para mais longe. E mesmo que pudéssemos avançar ininterruputamente crescendo o poder da CPU, estaríamos limitados velocidade de acesso de RAM, discos, redes.

Todo computador sempre terá um limite de capacidade e velocidade de processamento.


Os maiores computadores monolíticos, ou seja, cujo software é executado integralmente na mesma CPU, são os mainframes. O SERPRO usa mainframes para quase todos os processamentos de altos volumes, como tratamento do IR e o SISCOMEX (o sistema aduaneiro da RFB.)

Mainframes são o limite da máquina monolítica.
Mainframes são o limite da máquina monolítica.

Entretanto, enquanto a capacidade de cada máquina ficava cada vez maior, com valores proporcionais, tecnologias que se tornavam mais ordinárias se tornavam cada vez mais baratas. Ou seja, as grandes máquinas continuam caras como sempre, mas as máquinas baratas estão ficando cada vez mais poderosas, e isso abre uma possíbilidade interessante: paralelizar.

Custo do poder de processamento não cresce linearmente.
Custo do poder de processamento não cresce linearmente.

Superman & Batatas

Pense no seguinte: o Super-Homem é o cara mais forte e rápido do mundo. (Please, deixem o Flash fora disso…)

Suponha que um homem normal leva um minuto para descarcar uma batata, e que o Super-Homem leva, vai, um segundo. Isso quer dizer que ele pode descascar sessenta batatas no tempo que um homem normal descasca uma – e só! Nada além disso! Ele não consegue ficar mais rápido.

Bom, basta juntarmos 120 homens normais e teremos o dobro da velocidade do Super-Homem! Super-homens não existem por aí dando sopa, mas temos sete bilhões de humanos normais. Isso significa que, botando todos para descascar batatas, temos uma velocidade média de 116 milhões de batatas descascadas por segundo (million-peeled-potatoes-per-second, ou mppps kkkk…) Considerando-se que a produção mundial de batatas é de mais ou menos 1,88 trilhões de batatas (dados de 2013, supondo 200g de peso médio por batata), levaríamos aproximadamente 16.200 segundos para descascar tudo, ou quase cinco horas – menos de um dia de trabalho. A mesma tarefa feita pelo Super-Homem levaria mais de 520 milhões de horas, sem parar, ou quase um milhão e meio de anos!!

O mesmo pode ser feito com o processamento de dados: se uma máquina, sozinha, levaria um tempo X para realizar um processamento qualquer, duas máquinas iguais realizariam o dobro do processamento no mesmo tempo, ou poderiam completar a tarefa na metade do tempo.

Se podemos fazer isso, então nosso problema muda de figura: já não é mais como construir um computador super-rápido, mas sim como dividir nosso trabalho em pedaços iguais e processar esses pedaços em muitos computadores medianamente rápidos.

Construa seu próprio supercluster!
Construa seu próprio supercluster!

Bom, Bonito & Barato

E foi nesse problema que vários pesquisadores passaram a trabalhar na década de 2000. Em 2003, para vocês terem um idéia, ainda não existia nenhum “kit” pronto para processamento distribuído. Já existiam clusters, claro, mas eram coisas como o Beowulf, que nada mais eram que um monte de máquinas na mesma rede e alguns pacotes de software para ajudar a paralelizar a execução de determinado programa.

Nesse cenário o Internet Archive e a University of Washington se lançaram à busca de uma tecnologia que melhorasse a indexação de páginas web. Depois de algum tempo a equipe conseguiu produzir uma arquitetura clusterizada que dava uma performance superior em indexação, ainda que bem mequetrefe e instável, que acabou sendo chamada de Nutch. Segundo eles, era preciso uma pessoa ficar literalmente ao lado da aplicação o tempo todo, consertando os erros e defeitos.

… mas ao mesmo tempo outra empresa, uma com ainda poucos anos de vida, investia pesado em coisa semelhante.

Essa empresa, que não era ninguém menos que a Google, lançou dois papers, em 2003 e 2004, que se tornaram a fundação do que viria a ser o ecossistema de BigData. O primeiro falava sobre um cluster de sistemas de arquivo massivo, automatizado, o Google File System. O segundo propunha um modelo de programação para processamento paralelo, e expandia conceitos de uma tecnologia chamada programação funcional, desenvolvida no final da década de 1950 a partir dos conceitos de Cálculo Lambda, que por sua vez é da década de 1930. Esses conceitos resultaram em um framework, que é o segundo paper publicado, chamado de MapReduce. Esse paper mostrava como usar as operações funcionais de map() para distribuir a operação e reduce() para consolidar os resultados.

O gênio saíra da garrafa. :-)


A história toda é bem interessante, e vale a pena conhecer: clique aqui para ler a história inteira.


Eram os primeiros anos do Google, e uma outra empresa dominava então: o Yahoo. Buscadores de web (Google, Yahoo etc.) ganham dinheiro vendendo links e anúncios. Quanto mais páginas indexadas, maior sucesso nas buscas, e com maior sucesso, mais gente aparece querendo buscar. Quanto maior o público, a venda de anúncios cresce em número e valor.


Mais gente usando = maiores oportunidades de negócio.

Para aumentar o público, melhore seu produto = indexe mais.


Em 2006 o Yahoo investiu na reconstrução de seu motor de busca e começaram um projeto que incluíu os criadores da tecnologia que o Internet Archive estava desenvolvendo, o Nutch. O Nutch, que ainda existe aliás, era montado usando os conceitos do GFS e MapReduce. Quando o Yahoo encampou o projeto eles decidiram dividi-lo em dois pedaços: um webcrawler, que permaneceu com o nome Nutch, e uma infra-estrutura de clusterização, que englobava os pedaços trazidos do GFS e MapReduce. Já que eram tecnologias essencialmente diferentes, essa separação fazia todo sentido.

E que nome dar a este projeto?

Doug Cutting, que assumiu o projeto no Yahoo, nomeou-o a partir do elefante de pelúcia que seu filho chamava de, adivinhou, hadoop. Segundo Cutting, esse foi um bom nome porque era simples, sonoro, fácil de lembrar e sem nenhum significado em particular.

Ti fofu!!!! Had'oop!
Ti fofu!!!! Had’oop!

E o Que é BigData?

BigData é Hadoop, Hadoop é BigData. Ao menos no contexto geral, comercial, essa é a relação entre a tecnologia e o conceito: a tecnologia Hadoop ajudou a firmar o conceito de BigData, que por sua vez ganhou relevância conforme o Hadoop era aplicado em mais e mais casos de uso.

Em outras palavras, a maturação do Hadoop trouxe solução a uma classe de problemas normalmente fora do alcance. Esse sucesso turbinou o comércio dessas soluções, que acabaram sendo chamadas de BigData.

Hadoopen! Haduken! Shoriuken! Spining Round Kick-u-ken! Barbie e Ken!
Hadoopen! Haduken! Shoriuken! Spining Round Kick-u-ken! Barbie e Ken!

A certa altura o Hadoop ganhou status de cool, de pop, e caiu no gosto tanto dos capitalistas de risco. Daí surgiu uma leva de startups focadas em Hadoop, seus serviços, usos e todo o ecossistema tecnológico. E também caiu na graça da imprensa de tecnologia, que achou um nicho cheio de jargões fresquinhos e enigmas suficiente para uma década de reportagens.

Estamos agora em 2016 e, finalmentem, a força das buzzwords BigData/Hadoop está começando a esmaecer. Será preparação do palco para as próximas, como IoT?

O primeiro uso da expressão BigData foi em 1997, no artigo Application-controlled demand paging for out-of-core visualization para designar dados que não cabiam na memória do computador ou mesmo no disco. O resto é história: Hadoop acabou irreparavelmente associado ao termo. Apesar disso houve (e há) outras tecnologias para resolver problemas de “dados que não cabem na memória” do computador (e quase todas giram ao redor de clusterização.)

Por exemplo, existem bancos de dados especiais para aplicações computacionais intensas (muita conta e muito dado), como o Vertica e o Teradata. Ambos armazenam os dados de maneira diferente da de um banco relacional ordinário, e montam-se em clusters. Isso permite que distribuam as contas pelos nós, usando conjuntos locais de dados que depois se integram nos resultados em um nó mestre – que é exatamente a mesma idéia do Hadoop.

Pelo que vimos do histórico na primeira seção, existe um limite para o aumento da capacidade de processamento monomáquina, e portanto existe uma categoria de problemas que não pode ser tratada, dentro de tempos razoáveis, por esta arquitetura.

Resumindo:


Sempre que sua necessidade de processar dados extrapole a capacidade de uma só máquina e um tempo razoável, você está com um problema de BigData.


Podemos colocar de uma forma mais prática:

BigData é uma tecnologia de cluster de máquinas COTS2 para coleta e processamento de um grande volume de dados, dentro de um tempo razoável.

  • “Grande” é impreciso: qualquer coisa maior do que uma máquina simples consegue dar conta;
  • “Tempo Razoável”: mais imprecisão. Um tempo tal que os resultados são obtidos antes de tornarem-se inúteis.

Por exemplo, pode ser que os dados caibam todos no maior HD que você pode comprar, mas levariam anos sendo processados só para obter a primeira resposta – imagine as seguintes. Se você precisa da resposta em meses, anos é muito tempo. Se precisa de horas, semanas é muito tempo, e assim por diante.

Só que essa definição não é comercial, ela não “vende”. Foi quando começaram a surgir os acrônimos, sempre em tuplas de Vs, com cada vez mais vês: 3, 4, 5…

A primeira foi 3Vs: Volume, Velocity, Variety.

Alguns adicionaram um novo V, de veracidade, que queria dizer “qualidade”. Ou seja, não bastava acumular lixo, tinham que ser dados verdadeiros.

Outro colocou um V para valor, chegando a 5Vs, argumentando que se você não extrair valor dos dados, então não era BigData. E assim por diante.


Eu não consigo para de associar VVV com vai e volta, viu?, he he, ou com as variações. Por exemplo, meu primo usava 5 Vs: vai e volta voando, viu v******* ? :-D


Essa é a parte chata do mundo de TI, que tenta transformar conceitos e softwares em produtos com o mero balançar de beiços. Não caiam nessa! Só porque alguém escreveu uns slides (como eu fiz), montou um produto e está vendendo (que é quase o mesmo que estou fazendo…) não significa que ele está transmitindo um fato novo, uma verdade inegável ou algo supimpa. Use sua inteligência para filtrar o mundo.

No fundo tudo isso queria dizer a mesma coisa: problemas tão grandes que precisam de mais capacidade que uma só máquina pode fornecer.

Mas, ora vejam vocês, existem muitas opções para atender essa categoria de problemas!! Para começo de conversa existem máquinas SMP e multi-core. Existem clusters de bancos de dados, existem tecnologias de bancos de dados alternativos (como o Teradata ou o Vertica, que são colunares.)

Hadoop é uma destas tecnologias, que acabou ganhando fama por que seus limites situam-se muito acima dessas outras opções. (Mais imprecisão…)

Se precisássemos classificar os problemas pela capacidade de processamento requerido para resolvê-los, teríamos algo como isso:

  • Problemas normais: monomáquina;
  • Problemas grandes: Clusters de bancos (tradicionais e depois colunares;)
  • Problemas extremos: Hadoop.

Confuso? Complicado? Então guardem apenas isso:


BigData = Hadoop

Hadoop = BigData

BigData é a tecnologia de cluster de máquinas COTS2 para armazenamento e processamento de um volume de dados maior que cabe em uma só máquina, antes de o resultado ficar inútil.


Como sempre, essa definição é a minha, a partir do que eu aprendi. Você pode contestá-la (adoraria ouvir) ou achar outras. Como quase tudo em BI, vale a que você preferir. ;-)

Botando Para Rodar

Daí vem você e me diz: “Fábio, entendi patavinas do que você falou. Por analogia, algum destes temas tem a ver com o Hadoop/BigData?”

  • Inteligência de Negócios? Não mais que um banco de dados normal;
  • Armazém de Dados? De novo, mesma resposta (sem contar que projetos de DW incluem qualidade de dados e valor;)
  • PostgreSQL, Oracle etc? Esses são os famosos bancos relacionais, o que são bem diferentes – a começar pela forma de operação;
  • Sistemas transacionais (OLTP)? Os sistemas, em si, usam bancos transacionais. Como Hadoop é, grosso modo, um sistema que opera em lote, a resposta é não;
  • Linguagens de Programação? Não, nada a ver. Você pode implementar rotinas de MapReduce em algumas linguagens, mas Hadoop não é uma linguagem. Só para constar, programas MapReduce nativos são escritos em Java;
  • A Nuvem? De uma forma oblíquoa e não-relacionada, talvez. De maneira direta, nada a ver;
  • A Nuvem é BigData? Mesma resposta.

Se você precisa montar uma analogia para entender, meu caro, você está no sal, porque não existia nada como Hadoop antes. Pelo menos nada que fosse comum o bastante para ser um senso-comum. Sabe o que é Lustre? Já ouviu falar em MPI ou Beowulf? Pois é, Hadoop é uma mistura dessas coisas. ;-)

E todo mundo precisa de Hadoop? Ou de BigData? Não, claro que não. São raras as tecnologias que são aproveitadas indistintamente por qualquer organização. Hadoop não é uma dessas. Hadoop/BigData é uma tecnologia de nicho.


Veja que Hadoop(=BigData) é totalmente implementando com Software Livre. Logo qualquer um pode usar como e para o quê quiser, sem custos de licenças.


Como saber se você precisa? Fácil: sua organização enfrenta algum problema causado pelo mero volume dos dados? Se tem, pode ser que precise. Se não, então nem se dê ao trabalho. Simples assim.

Claro que podem existir problemas que você ainda não sabe que tem, e que podem vir a ser tratados com Hadoop, mas esses fazem parte de um conjunto mais ou menos pequeno. Vejamos um pouco sobre isso.

É Online?

Hadoop foi projetado para ser operado por meio de programas MapReduce. Isso é qualquer coisa, menos online. Problemas online, em geral, dizem respeito a registrar transações e hoje a melhor opção para isso ainda são bancos de dados relacionais. Em alguns casos, um mainframe é a única solução.

Por exemplo, caixas do Pão de Açúcar eram operadas por mainframe. Não sei como é hoje, mas até meados da década passada cada checkout do Pão de Açúcar era ligado a um mainframe, com operações de enorme volume de dados acontecendo em tempo real.

Isso não quer dizer que essa possibilidade está barrada ao Hadoop. Muito pelo contrário: existe muita pesquisa e desenvolvimento sendo conduzido para reduzir e até eliminar os overheads do Hadoop e colocá-lo em “modo online”. Em última análise, esse caminho vai nos levar até o ponto de processamento transacional, operacional.

Mas, hoje e pelos futuro próximo, Hadoop é algo que opera em batches, não online.

Se você precisa de operações online em grande volume (OLTP), como ERP, invista em grandes computadores e até mesmo em mainframes. Por enquanto, Hadoop não é uma tecnologia para esse tipo de aplicação. Um dia, quem sabe?

DataLake?

Esse é um conceito idealizado pela própria Pentaho. A meta deles era popularizar o uso do Hadoop, e com isso alavancar o consumo de Pentaho, já que esse tem enormes facilidades para lidar com Hadoop.

Em tese, DL é um substituto para um Data Warehouse, um armazém de dados. O problema é que, hoje, Data Lake é uma coisa bagunçada e crua. Para a empresa consumir os dados de um Data Lake é preciso que um profissional trabalhe os dados que estão lá e construa outras estruturas, normalmente fora do Hadoop, que serão consultadas pela comunidade de usuários da organização.

Só que ao fazer isso caímos de novo no modelo de Armazém de Dados, que faz exatamente a mesma coisa.

E se a dita empresa quiser se livrar desse profissional intermediário, ela terá que deixar cada cliente, cada usuário, construir seus próprios usos. O que vai requerer que esses usuário conheça não apenas o negócio, mas também conheça intimamente os dados – ou nada vai sair!

No fundo, DL, tal como se apresenta hoje, é uma tentativa de criar um produto comercial, de linha de frente, com um insumo que só funciona bem em certas situações, mas não em todas. Atualmente eu não vejo nenhuma vantagem nele – especialmente se considerarmos Data Vault.

Machine Learning

O termo Machine Learning é um tipo de expressão guarda-chuva para acomodar um monte de tecnologias. Grosso modo, Machine Learning, ou Knowledge Discovery etc., são termos relacionados à área de Data Mining.

Data Mining é o processo – não o software! o processo! – de examinar dados em busca de um modelo matemático que permita usar o passado para prever o futuro.

Um exemplo simples é a previsão do tempo: depois de analisar os dados meteorológicos acumulados por décadas, fomos capazes de construir uma equação – um modelo matemático – que dá a probabilidade de ocorrer ou não chuva em um determinado lugar, em um determinada dia e hora.

Podemos aplicar o mesmo tipo de técnica a coisas mais prosaicas como sugerir um produto para nosso cliente, oferecer um desconto para ajudá-lo a fazer uma compra ou negar qualquer desconto. Podemos analisar os dados de tráfego em uma cidade e descobrir uma sequência de acionamento de semáforos para reduzir congestionamentos. Podemos analisar os caminhos produtivos de uma fábrica e mudar seu layout para reduzir custos, aumentar a produtividade ou prevenir defeitos.

Machine Learning é justamente uma técnica de descoberta de um modelo que explique os dados. Como volume é uma variável crítica para o sucesso de técnicas de ML, Hadoop e BigData têm sido associados a ML, mas não são, de forma alguma, sinônimos.

NoSQL?

NoSQL já foi descrito como not SQL e mais recentemente como not only SQL, e refere-se de maneira geral ao mecanismo de consulta de uma base de dados. Hoje entende-se por NoSQL como uma expansão nas técnicas de manuseio de dados em bancos para além de mero SQL.

Hadoop, que é alimentado por operações de transferência de arquivos e consultado por MapReduce, é considerado uma tecnologia NoSQL. Entretanto, NoSQL não é sinônimo de Hadoop, da mesma forma que não é sinônimo de MonetDB, CouchDB e outros famosos bancos NoSQL.

Curiosamente, há um grande esforço para conseguir “equipar” Hadoop com SQL! Vai entender…

IoT?

Internet das Coisas, pelo que tudo indica, é a próxima BuzzWord a estourar nas paradas. E aí, qual é a relação entre IoT e Hadoop/BigData?

A visão trazida pelo conceito IoT diz que todos os eletrodomésticos e traquitanas terão, cada um, seu próprio IP e trocarão dados entre si e com computadores. Para que propósito, exatamente, é um tópico à parte. O que nos interessa, hoje, é notar que o volume de dados estima-se que será gerado é muito (muito (muito!)) maior que as maiores plataformas atuais trabalham. Logo, analisar esses dados será tarefa para Hadoop – até mesmo transacioná-los talvez venha a ser feito por uma plataforma similar.

Logo, IoT não é sinônimo de BigData, ainda que com certeza possuam uma forte ligação.

Que Problemas Resolve?

Vocês hão de concordar comigo que essa pergunta é um pouco boba. Afinal, se BigData trata de processar dados que não cabem na RAM ou no disco local, então BigData (que é o mesmo que falar “Hadoop”) resolve problemas… com dados demais!

O critério para saber se você – sua empresa, sua organização – precisa de uma solução de BigData não é o tipo de negócio, o porte da organização ou o alcance dela. O critério é ter coisa demais para processar e, mesmo com uma máquina maior, ainda continuar a ser coisa demais, ou nunca ser rápido o bastante.

Por isso, se algum fornecedor te pestear para oferecer BigData, ponha um pé atrás. Assista a apresentação dele e pergunte-se sempre, o tempo todo, “não dava para fazer com ( ) um banco tradicional? ( ) um banco colunar? ( ) um cluster? ( ) alguma outra coisa mais fácil ou barata? ( ) etc?”.

Voltando ao ponto, graças a paralelização massiva, Hadoop/BigData arquiva e processa dados com uma grande velocidade. Que categoria de problemas conhecemos, ao menos em BI, que causa grande processamento?

Relatório? Não, nem de de longe.

OLAP? Mais ou menos, talvez, mas via de regra, não.

Painéis? Menos ainda…

Data Mining?

Isso mesmo: Hadoop barateia Data Mining. Sempre que você precisar de Data Mining, e a performance do seu parque estiver abaixo do que você precisa, adotar Hadoop pode melhorar sua vida com uma relação custo-benefício sensivelmente melhor que outras tecnologias. Mas cuidado: melhor relação custo benefício olhando apenas hardware e software! Sem mão-de-obra qualificada, pode ser que seja tão difícil montar e operar um cluster Hadoop que outras soluções mais caras podem ter, no final, uma relação custo-benefício mais interessante!


SEMPRE considere a necessidade, o custo e a disponibilidade de mão-de-obra especializada!! SEMPRE!!!


E, claro, Hadoop é uma boa opção toda vez que for preciso arquivar um grande volume de qualquer coisa que não seja usado online, como arquivos, históricos, logs etc.

Profissional de BigData?

Gostou do que viu? Tem interesse em saber no quê trabalha, quanto ganha e que sofrimento passa um profissional dessa área? Enfim, é a sua vida… ;-)

Há duas grandes áreas: Infra-estrutura e Aplicação em si.

Como o próprio nome diz, montar e sustentar a infraestrutura de um cluster Hadoop requer conhecimento multidisciplinar: redes, sistemas operacionais, Linux (fundamental!) e assim por diante. Até ajuda saber programar Java, ou no mínimo entender o assunto, mas não é um pré-requisito. Invista em cursos de qualidade, começando por um sobre Hadoop e depois avançando nos sub-tópicos. Isso vai te dar capacidade para entender os problemas que assolam ambientes Hadoop e a fazer otimizações mais sofisticadas, te distinguindo no mercado de trabalho.

Agora, você gosta mesmo é de sujar as mãos escovando bit até deixar um algoritmo tinindo de brilhante, seu caminho no Hadoop é praticamente o mesmo de um Analista de Data Mining: é obrigatório conhecer bem e ter experiência com Estatística e Matemática. A partir daí é necessário saber transformar esse conhecimento em modelos matemáticos a partir dos dados disponíveis, o que é feito usando-se o ferramental de Data Mining, como R, RapidMiner, SAS Enterprise Miner, SPSS, Python e/ou similares.

Mas todo esse conhecimento é apenas para sua fundação. O profissional que vai fazer a diferença, que vai elevar seu salário à estratosfera é aquele que tiver visão de negócio e habilidades de desenvolvedor. É aquele que souber entender o negócio da empresa e traduzir aquilo em perguntas aos dados, e a moldar as respostas em conceitos que possam ser transformados em algoritmos.

Esse sempre foi, é e sempre vai ser O cara. ;-)

Hoje em dia essa função leva um nome vistoso, para o qual eu sempre torço o nariz: Cientista de Dados. No fundo, porém, o mesmo de sempre: Analista de Data Mining.

Conclusão

Meu propósito era ajudar os alunos da FATEC a entrar com o pé direito no tema. Não tenho como avaliar o resultado e saber se eu atingi ou não esse objetivo. O feedback dos alunos foi bastante positivo, e a recepção foi boa. No mínimo, portanto, eu atendi a um anseio deles.

Uma coisa que me chamou a atenção foi o fato de ter ali não apenas cursos de TI em geral, mas também alunos do curso de Secretariado Executivo. Porquê? Oras, se tem uma coisa que é distante de BigData, em uma empresa, é a disciplina de administração/secretariado/gestão em geral. Mesmo que se argumente que BigData é o futuro e que logo a estratégia da empresa vai estar calcada em resultados obtidos graças à essas tecnologias, me parece um exagero colocar o assunto em uma faculdade tão distante de TI quanto Secretariado. Na minha opinião, é o mesmo que ensinar bancos de dados transacionais para o pessoal de Biblioteconomia porque usam sistemas OLTP.

Essa observação alimentou minha palestra seguinte, na PUC do Rio Grande do Sul. Mas isso é o assunto do próximo post.

Até lá! ;-)


  1. Uma expressão inglesa, “to add insult to injury” 
  2. Common-Of-The-Shelf, ou “de prateleira”. Significa coisas padronizadas, baratas – algo como uma commodity

Eleições Inteligentes

Agora que estamos na época, diga-me: como você escolhe seu candidato às eleições?

Essa é uma escolha pessoal (mas de arrependimento coletivo :-) ) e não tem uma fórmula. Cada um vota de acordo com sua consciência e opinião.

Não deixa de ser curioso, portanto, os argumentos que cada político apõe à sua campanha. Um dos candidatos a vereador em São Paulo, por exemplo, promete acompanhar de perto os gastos públicos. Para dar um exemplo do que está falando, ele soltou uma lista das emendas aprovados na câmara dos vereadores, que geraram despesas.


Hmmm… Dados tabulados… Planilha…


É claro que eu não pude resistir e, morando em São Paulo, eu tinha que fazer um exame mais visual desses dados.

Assim Não Vai Rolar…

Eu poderia usar o Calc (=Excel do LibreOffice) ou qualquer outra ferramenta. Optei pelo [BA Server 5.4][ba54] que me permite importar um arquivo CSV e montar um cubo. Assim eu poderia examinar os dados e montar um post para o blog. Eu estava farejando um caso neste assunto.

Eu me propus a uma tarefa muito simples:


Examinar os gastos das emendas de vereadores, no período 2013-2015, contra as principais dimensões: Vereador, Destino da Verba e Tempo.


Não queria achar nenhum padrão oculto nem nada, apenas exercitar um pouco de ETL/OLAP com o Pentaho e aproveitar para ver como o dinheiro está sendo gasto.

Expertei a planilha para CSV e importei no BA Server usando o wizard de nova fonte de dados. Isso me deixou com um cubo OLAP, “pronto” para explorar.

Primeira Visão: Por Vereador

Coloquei entre aspas porque estava pronto coisíssima nenhuma. Vejam:

Valor de emenda aprovada, quebrado por vereador.
Valor de emenda aprovada, quebrado por vereador.

O nome do verador pode aparecer de mais de uma forma, resultando em linhas que não são agregadas. Assim parece que temos dois vereadores “tipo Netinho”, cada qual com um total de gastos, quando na verdade é um só político:

Vereador Gasto
Netinho de Paula 180.000,00
Netinho De Paula 660.000,00
Netinho de Paula”_” 560.000,00

O “_” é para indicar que o nome possui um espaço extra ao final, dando três “nomes” diferentes para a mesma pessoa.

E apesar de o objetivo ser examinar os valores por vereador, se eu quisesse ver por partido, quantidade de votos etc. não daria, pois essa informação não consta na planilha.

Segunda Visão: Por Objeto

Vamos lá:

Valor de emenda aprovada, quebrado por objeto, i.e. destino da verba.
Valor de emenda aprovada, quebrado por objeto, i.e. destino da verba.

Nossa, pior ainda! Até há um padrão de nomes, mas não é consistente (nomes duplicados de formas diferentes, como no caso dos vereadores) nem prático (não dá para analisar um gráfico com um item “Reforma do CDC Moinho Velho, no bairro do Ipiranga, incluindo troca do piso do salão de festas, do salão sede, do vestiário e sanitários, troca do telhado, instalação de forro de gesso no salão de festas, reforma da parte elétrica/luminárias, além de pintura geral – Rua Elba 980 – Ipiranga”!!)

E também não dá para separar por categorias, como Saúde, Esporte, Reforma, Compra etc. Até temos que orgão recebeu o dinheiro, mas não vai além disso. Não dá para, por exemplo, comparar os gastos de subprefeituras com secretarias municipais.

Terceira Visão: Por Ano

Até temos um padrão melhor, graças ao fato de termos uma coluna só para ano:

Valor de emenda aprovada, quebrado por ano.
Valor de emenda aprovada, quebrado por ano.

… mas não dá para quebrar por mês, por exemplo, ou para saber qual dia da semana tem mais aprovações.

Também não dá para quebrar por região da cidade ou qualquer outro parâmetro, como quantidade de eleitores, por exemplo. Imagine saber quais são os projetos que atendem mais pessoas? Será que tem algum padrão bairrista, onde somas vultosas são gastas com projetos populistas, mas de baixa serventia pública? Isto é, que é bonito pra chuchu, mas atende pouca gente?

Data Quality To The Rescue!

Eu sempre quis fazer um post com exemplos de Data Quality, e estava apostando que esta planilha seria um bom caso.

Há uma renca infinita de operações e técnicas de limpeza de dados, mas na maior parte dos projetos sempre usamos as mesmas técnicas. Duas destas técnicas mais frequentes são muito úteis, e se aplicam diretamente ao ETL: normatização e classificação dos dados.

Por exemplo, o “multi-vereador” que vimos acima passaria a ter um único nome, e as agregações passariam a funcionar. Isso é normatização: damos uma norma aos membros de um conjunto, que obtemos montando – manual ou automaticamente – um dicionário para traduzir todas as formas de cada elemento em uma forma só.

Já a classificação é uma técnica que automatica extrai atributos de um certo elemento. Por exemplo, podemos usar a data, que existe na planilha, para conseguir as informações de mês e dia da aprovação do gasto.

Em outro exemplo, podemos fazer buscas por textos específicos em cada linha tratada, e assim gerar uma classificação automática para os dados. Vou usar essa técnica para tratar os objetos de cada emenda, e descobrir se pertencem à área da Saúde, Esporte ou Cultura, se são Melhorias ou Compras e assim por diante.

Vamos lá.

Normatização com Dicionários

Com relação ao nome dos vereadores, precisamos montar um dicionário que “traduz” cada variação de nome para um padrão. E já que estamos nesta, podemos fazer um pouco mais: podemos enriquecer essa planilha com outros dados do vereador, como partido, quantidade de votos conquistados etc.

Na verdade podemos fazer a mesma coisa com tudo nesta planilha:

  • Orgão: tipo (Secretaria, Subprefeitura, Autarquia etc.);
  • Região da cidade atendida: Centro, Sul, Leste, Oeste, Norte;
  • Objeto: usufrutuário, prazos etc.

Imagino que a Câmara dos Vereadores registre esses e muitos outros atributos em seus sistemas, mas o que temos é só essa planilha e por isso não dá para extrapolar demais.


O nome do vereador na planilha original vem com maiúsculas e minúsculas. A primeira coisa mais fácil a fazer é mudar todos para caixa baixa ou alta – prefiro alta.

Daí podemos pegar o partido, votação etc. do vereador em algum site. Eu achei uma página do UOL sobre as eleições de 2012 que trazia tudo: nome do vereador, partido e quantidade de votos. Com isso tudo em mãos eu construí uma planilha Excel com o seguinte layout:

Coluna Função
VEREADOR_ORIGINAL Nome do vereador na planilha original
VEREADOR_CORRIGIDO Nome corrigido
PARTIDO Partido pelo qual ganhou a eleição
VOTOS Quantidade de votos recebidos pelo vereador
VOTOS PARTIDO Quantidade de votos recebidos pela legenda

A tabela abaixo mostra como essa tabela foi preenchida:

VEREADOR_ORIGINAL VEREADOR_CORRIGIDO PARTIDO VOTOS
Abou Anni ABOU ANNI PV 
Adilson Amadeu ADILSON AMADEU  PTB  40100
Adolfo Quintas ADOLFO QUINTAS PSDB 
Alessandro Guedes ALESSANDRO GUEDES PT 
Alfredinho Alfredo Alves Cavalcante (ALFREDINHO) PT  36634
Andrea Matarazzo ANDREA MATARAZZO  PSDB  117617

Porque há casos de nenhum voto? Não sei. Provavelmente é um vereador suplente, que não constava na lista que eu usei. Dá para corrigir, mas o propósito deste post é exemplificar algumas técnicas de Data Quality e por isso não me preocupa se sobrar algumas lacunas.


Depois eu fiz mais duas colunas: faixa_votos_1 e faixa_votos_2. A primeira qualifica o vereador em faixas de 10.000 em 10.000 votos. A segunda faz uma divisão em três categorias: menos de 50.000 votos, entre 50.000 e 100.000 votos, e uma última de mais de 100.000 votos.

Depois eu apliquei a mesma idéia para o orgão e criei este dicionário:

Coluna Função

| ORGAO_EXECUTOR_ORIGINAL | Orgão na planilha original |
| ORGAO_EXECUTOR_CORRIGIDO | Nome do orgão corrigido |
| TIPO_ORGAO | Tipo: secretaria, autarquia etc. |
| REGIAO_CIDADE | Região que atende, ou Geral quando não tem |

Que, preenchido à mão, ficou assim:

ORGAO_EXECUTOR_ORIGINAL ORGAO_EXECUTOR_CORRIGIDO TIPO_ORGAO REGIAO_CIDADE
Autarquia Hospitalar Municipal AUTARQUIA HOSPITALAR MUNICIPAL AUTARQUIA GERAL
Fundo de Preservação do Patrimônio Histórico e Cultural FUNDO DE PRESERVAÇÃO DO PATRIMÔNIO HISTÓRICO E CULTURAL FUNDO GERAL
Fundo Municipal de Assistência Social FUNDO MUNICIPAL DE ASSISTÊNCIA SOCIAL FUNDO GERAL
Secretaria Municipal de Coordenação das Subprefeituras SECRETARIA MUNICIPAL DE COORDENAÇÃO DAS SUBPREFEITURAS SECRETARIA MUNICIPAL GERAL
Secretaria Municipal do Verde e do Meio Ambiente SECRETARIA MUNICIPAL DO VERDE E DO MEIO AMBIENTE SECRETARIA MUNICIPAL GERAL
Serviço Funerário do Município de São Paulo SERVIÇO FUNERÁRIO DO MUNICÍPIO DE SÃO PAULO AUTARQUIA GERAL
Subprefeitura Pinheiros SUBPREFEITURA PINHEIROS SUBPREFEITURA OESTE
Subprefeitura Sé SUBPREFEITURA SÉ SUBPREFEITURA CENTRO
Subprefeitura Vila Mariana SUBPREFEITURA VILA MARIANA SUBPREFEITURA SUL
Subprefeitura Vila Maria/Vila Guilherme SUBPREFEITURA VILA MARIA/VILA GUILHERME SUBPREFEITURA NORTE
Subprefeitura Vila Prudente/Sapopemba SUBPREFEITURA VILA PRUDENTE SUBPREFEITURA LESTE

Classificação Automática

Resolvidas essas dimensões, restou apenas o objeto de cada emenda. O que contém a lista de objetos de emendas? Coisas assim:

  • Contenção Margem com Gabiões – Rua Magdeburgo – Processo nº 2013-0.102.577-8;
  • Readequação área de lazer Rua Constantino Cavafi – Processo nº 2013-0.102.541-7;
  • 26º Campeonato de Moto Aquática – Jet Ski – Associação Brasileira de Jet Ski Profissional e Não Profissional;
  • E172 – Realização de Duas Etapas da Copa São Paulo de Jet Ski na Represa do Guarapiranga;
  • Execução de Obras de microdrenagem nas Ruas Rodrigues dos Santos, joão Teodoro e Ruas limitrofes no Bairro do Brás;
  • Associação Beneficente Nossa Senhora do Pari – Melhorias e Ampliação de Atendimento para adequação, ampliação e reforma do mobiliário e equipamentos hospitalares referente ao setor de Nutrição e Dietética;

E assim por diante. A única forma de fazer uma classificação precisa, bem-feita, é manualmente. São quase 1.800 projetos aprovados. Se eu levar um minuto para qualificar cada um, são 1.800 minutos ou 30 horas trabalhando sem parar.

No $%#%!@% way.

Logo, ou achamos o sistema de origem e vemos o que mais dá para puxar, ou montamos uma aproximação. Por exemplo, podemos montar uma tabela com uma coluna para cada atributo, como “É uma compra de material/produto?”, “É um pagamento de serviço?”, “É um gasto com saúde?” e por aí vamos. Daí, para cada objeto que entrar nesta tabela na primeira coluna, respondemos as perguntas em outras colunas. No final teríamos algo assim:

Objeto Compra? Cultura? Saúde? Esportes?
E2538 – Fundação Antonio Prudente(…) Não Não Sim Não
Implantação de equipamento de Ginástica (…) Sim Não Não Sim
Realização de obras e pavimentação de vias, visando a melhoria (…) Não Não Não Não
Incentivo à pratica de esportes Não Não Não Sim

Isso permitiria uma classificação rudimentar, inicial, que desse ao menos uma visão geral. Com ela podemos responder perguntas como “quanto do gasto é compra de material novo, e quanto é manutenção?” Ou “quanto estamos alocando de dinheiro para Saúde, Educação e Lazer?”

Uma forma de se fazer seria colocar essas linhas em uma planilha Calc e uma coluna para cada pergunta. Daí, usando fórmulas como IF() e FIND(), buscamos as ocorrências de termos-chaves. Sempre que encontrarmos um, marcamos com “SIM”. Se não encontramos nada, com “NÃO”.

E, de fato, foi a primeira coisa que eu fiz:

Primeira tentativa de qualificar os objetos.
Primeira tentativa de qualificar os objetos.

Era uma solução muito tosca, mas me ajudou a entender a mecânica da coisa. Com isso eu pude subir para o nível seguinte: usar RegEx, isto é, Expressões Regulares para fazer essa detecção. Usando expressões regulares eu poderia montar um processo de detecção automático e mais robusto que uma planilha Excel.

Assim, aproveitei o que eu aprendi com o livro RegEx Com Python e, com o auxílio do passo Regex Evaluation consegui extrair essa informações do nome do objeto de cada emenda parlamentar.


Eu parei de criar atributos e de refinar minhas RegExes quando comecei a ter um resultado aproveitável, mas poderia ter ido mais longe e conseguido bem mais coisa – até mesmo reconstruir a descrição da emenda aprovada. Mas, de novo, não era essa a meta e por isso não avancei.


Transformação Eleições 2016

A figura abaixo dá a visão geral da transformação que lê a planilha e gera um CSV pronto para importação no BA Server:

Transformação que incrementa a qualidade dos dados da planilha.
Transformação que incrementa a qualidade dos dados da planilha.

Essa transformação, e todos os dicionários, resultados e um pouco mais, estão disponíveis para download aqui, como um zip. Descompacte em um diretório qualquer e abra os arquivos .KTR com o Spoon do PDI 5.4. Falarei mais sobre a outra transformação na Conclusão.

Agora Sim!

Muito bem, com um novo e melhorado conjunto de dados, recarreguei o CSV no BA Server e gastei um tempinho refinando o mapeamento. Vejamos o que podemos fazer agora.

Por Vereador: bem melhor! Agora dá para ver todo mundo, numa só posição.

Valores aprovados por vereadores em São Paulo, no termo 2012-2016.
Valores aprovados por vereadores em São Paulo, no termo 2012-2016.

Veja que existe apenas um vereador que aprovou menos de um milhão de Reais em emendas. Até dá para dizer que existe duas faixas:

  • Uma turma que libera muito, com totais sempre maiores que R$ 5.000.000,00;
  • E outra que é mais modesta, que fica entre os R$2M e R$4M.

Mesmo assim não temos nenhum “calombo”, que seriam vereadores que liberam (ui!) muito mais que a média (ai!). Eu diri até que eles se espalham em uma graduação mais ou menos suave.

Por Objeto: Agora sim! Mesmo sendo uma classificação incipiente, consegui ver que os dez maiores valores em gastos concentram-se em coisas que não é nem para Saúde, nem para Esportes ou para Cultura.

Valores aprovados por qualificação de objetos.
Valores aprovados por qualificação de objetos.

Os dois picos são muito curiosos… Daí eu fui olhar por orgão:

Valores aprovados por orgão.
Valores aprovados por orgão.

Uia. Quem mais recebe dinheiro de emenda parlamentar… é a Secretaria de Esportes e Lazer, mas os picos do gráfico anterior mostram que o grosso do dinheiro não vai para isso… Confuso! Com certeza culpa da classificação porca e apressada que minhas expressões regulares toscas.


Eu explorei essas visões um pouco mais do que eu vou mostrar aqui. A menos que eu tenha cometido um erro grosseiro, parece que há mesmo uma concentração de emendas para Secretaria de Esportes. Eu fiquei pensando sobre o quê explicaria isso, e bolei uma hipótese: eventos e ações voltadas para Esportes causam um impacto mais marcante, e não constumam ser caras. Assim, se um político precisa prometer algo que tenha condições de cumprir, prometer fazer um evento esportivo parece uma opção de boa relação custo-benefício.

Mas é só uma hipótese, sem nenhum embasamento sério nos fatos. Tipo assim, um chutão. ;-)


E eu continuei a cutucar os dados, até que me deparei com uma visão interessante:

Eleitores representados por gastos.
Eleitores representados por gastos.

Lemos esse gráfico assim: “O maior valor foi liberado para emendas criadas por parlamentares com representação menor que 50.000 votos”. Legal, não é? Como a maior quantidade de vereadores tem menos que 50.000 votos, ter a grana concentrada nessa parcela de políticos significa que o dinheiro está sendo empregado em projetos da maioria dos vereadores, e que são projetos de baixa representatividade, ou seja, tocados por políticos que representam poucos eleitores.


Eu sou partidário do voto distrital, e não da forma atual. Esse gráfico reforça meu viés pelo voto distrital, mas evitaria tomá-lo como uma prova inconteste da vantagem dessa opção.


Essa é uma visão difícil de ler, mas é bem curiosa:

Valores em ementas espalhados na área proporcional a cada orgão.
Valores em ementas espalhados na área proporcional a cada orgão.

Imagino que era para ser um gráfico de árvore, mas ficou meio estranho…

Ele representa o valor gasto por orgão, dentro de cada tipo (Fundo, Subprefeitura etc.) De novo, observe como parece haver alguma desproporção entre os valores alocados à Secretaria Municipal de Esporte e Lazer e, por exemplo, a de Saúde. Até a de Cultura é maior que a de saúde!

E o gasto ao longo do tempo? Não parece nada de mais, um comportamento quase aleatório:

Distribuição de valores nos meses de aprovação.
Distribuição de valores nos meses de aprovação.

Eu poderia prosseguir aqui até a próxima eleição… de 2018. Mas não é preciso tanto. ;-)

Conclusão

Diz o ditado: Lixo Entra, Lixo Sai. Análises de dados dependem de dados Limpos, bem tratados etc. Existem muitas formas de se cuidar dos dados para que eles possam nos contar a verdade por trás de si. O ramo que responde por essas técnicas chama-se Data Quality e costuma ser uma disciplina complexa.

Vimos que, mesmo sendo trabalhoso, qualquer melhoria pode render ganhos significativos. Por isso considere sempre fazer ao menos uma avaliação da qualidade dos seus dados que o cliente vai examinar.

Coceira…

Com os dados ali, prontinhos, e os assuntos separados em tópicos, eu fiquei com a mão coçando para andar mais um pouco e transformar aquilo em uma estrela dimensional. Como a melhor maneira de se livrar da tentação é ceder, eu cedi.

Peguei a transformação anterior e coloquei alguns passos que alimentam junk dimensions. Isso deu origem a dimensões instantâneas de Vereador e Orgão.

Modelo dimensional miojo: basta adicionar Junk Dimensions!
Modelo dimensional miojo: basta adicionar Junk Dimensions!

Depois eu juntei todos os atributos em uma dimensão junk de verdade, e mais adiante adicionei outra para os objetos das emendas. Eu poderia degenerá-lo mas, francamente, a idéia daquele texto todo na fato, uuhhh calafrios, não me agradou.

Por fim criei uma dimensão data completa, usando um passo Database Lookup. Pronto! Um Table Output no final, sair clicando em todos os botões SQL para criar tabelas, rodar e…. PIMBA! Tudo no ar!

Eu peguei o Power*Architect e fiz uma engenharia reversa no banco. Ajustei alguns detalhes (como os relacionamentos) e voilà! Modelo dimensional de valores de ementas!

Diagrama de tabelas da estrela Emendas Vereadores 2013-2015.
Diagrama de tabelas da estrela Emendas Vereadores 2013-2015.

Esse diagrama e a transformação que o alimenta estão no mesmo pacote deste post. Fique à vontade para brincar, explorar e descobrir. Apenas mantenha em mente o seguinte:


Eu, Fábio, não sou responsável pelo conteúdo de dados deste pacote, nem por qualquer interpretação que alguém tirar dele.

Me incluam fora dessa! ;-)


Até a próxima!

Servidor Pentaho com Vagrant

Em um post anterior eu resenhei um livro da Packt que ensina como usar o Vagrant para criar ambientes de desenvolvimento. Lá eu comentei sobre como Vagrant é interessante, e até como eu tentei montar um servidor, mas não consegui. Ainda tenho muito que aprender sobre Puppet para fazer a coisa tão bem, mas vou dividir com vocês o que eu fiz. Na pior das hipóteses é um ambiente Pentaho pronto, e pode quebrar um bom galho.


Antes de mais nada eu preciso deixar claro que vou falar sobre o Pentaho por mera conveniência. Dá para aplicar tudo que eu vou falar aqui em qualquer plataforma, com quaisquer softwares de BI. Pentaho é do balacobado, mas cada um é livre para montar seu projeto como achar melhor. Eu gosto de software livre, lembram-se? Isso significa liberdade para usar o software que quiser. ;-)


O primeiro post caiu direto no assunto, e ficou meio “seco”. Por isso vou começar revisando a idéia toda com mais cuidado. Depois eu vou mostrar como fazer e, na conclusão, detono tudo. (Tee-he)

Processos & Ambientes

Desde sempre, e não apenas hoje em dia, qualquer projeto de BI sempre possuiu duas etapas: colher dados e usar dados.

A parte de colher os dados equivale à montagem de um DW, um Armazém de Dados. Já a parte de usar os dados corresponde a um projeto de Data Mining ou a um projeto que expõe os dados aos usuários por meio de ferramentas de análises.

Quando o projeto é pequeno podemos desenvolver na produção e simplesmente lidar com as consequências dessa bagunça, mas quando os projetos são maiores que um certo porte, esse “simplesmente” não se aplica mais. Precisamos de pelo menos dois ambientes: um de desenvolvimento e um de produção.

O problema é que manter dois ambientes separados acaba por originar discrepâncias entre eles, e aos poucos começam a ficar diferentes um do outro. Depois de um tempo as diferenças são tamanhas, e tão irreconciliáveis, que cada nova versão levada para produção gasta um tempo só ajustando o código para as diferenças.

E é neste ponto que a idéia de infraestrutura como código pode nos ajudar: ao invés de mantermos dois ambientes com configurações manuais, descrevemos cada ambiente com um código-fonte, tal qual um software. Desta forma mantemos um controle muito maior sobre cada configuração e, melhor ainda, podemos comparar ambas e evitar as discrepâncias que acabam por atolar o projeto a cada nova versão.

Softwares como Puppet e Chef cuidam para que as definições desse “código” sejam aplicadas e respeitadas. Sempre que um servidor sofre alguma mudança que o desvia de sua configuração “correta”, esses programas, chamados genericamente de provisionadores, forçam a configuração de volta, apagando as coisas erradas e restaurando as configurações definidas pelo projeto.

O Vagrant é um passo na direção de infraestrutura como código: ao invés de construirmos um servidor, simplesmente definimos um servidor virtual. Associado a provisionadores, conseguimos um projeto cuja configuração é uniforme de ponta-a-ponta. Mais: podemos trabalhar em projetos distintos, tendo um ambiente de desenvolvimento finamente ajustado para cada projeto, se um interferir com outro.

Se durante o desenvolvimento descobrimos que precisamos alterar alguma configuração, essa alteração entra no código que descreve o servidor, ao invés de ficar perdida em um manual qualquer. Por meio de um versionador, como Git, esse código de infra-estrutura entra no projeto e é distribuído para todos os envolvidos. Mais ainda, sendo versionado e propagado para a produção! É um mundo perfeito – ou não? ;-)

Vagrant BA Server

Agora eu vou mostrar para vocês a sequência de ações que eu tomei até construir um Pentaho BA Server apto a atender um projeto simples. Não é o resultado final perfeito, que eu gostaria de obter, pois ele não envolve nenhum provisionador – ainda estou batendo cabeça com isso, e não queria demorar para levar isso a vocês. Esse campo ainda está muito cru, e quanto antes essas idéias começarem a se espalhar por aí, melhor.

O processo é relativamente simples:

  1. Instalar o VirtualBox;
  2. Instalar o Vagrant;
  3. Criar um ambiente Vagrant;
  4. Adequar os parâmetros desse ambiente para o BA Server;
  5. Instalar o Pentaho BA Server.

Eu fiz tudo isso em Ubuntu 16.04-64bits, um Linux, mas deve ser possível repetir esses passos com Windows e Mac, já que eles são suportados.

Todas essas ações são tediosamente sem graça em Ubuntu:

  1. Abri um terminal e comandei sudo apt-get update, para atualizar os repositórios de pacotes;
  2. Instalei o VirtualBox comandando sudo apt-get install virtualbox;
  3. Instalei o Vagrant: sudo apt-get install vagrant;

    O site do Vagrant adverte as versões de repositório normlamente estão bem defasadas em relação ao projeto, e que não raro podem acabar apresentando problemas. Por isso, recomendam eles, baixe o instalador do site (aqui) ou compile o projeto do zero.


  4. Criei um ambiente Vagrant:
    1. Em outro terminal criei um diretório para o novo servidor: mkdir AmbienteVagrant;
    2. Entre neste diretório com cd AmbienteVagrant e criei o arquivo inicial: vagrant init precise32 http://files.vagrantup.com/precise32.box;
  5. Configurei esse ambiente para ter 1.5 GB e expor a porta 8080:
    1. No diretório AmbienteVagrant surgiu o arquivo Vagrantfile, que eu abri com o editor de textos;
    2. Entre as linhas que definem a configuração, Vagrant.configure(2) do e end, inseri esses dois trechos: config.vm.provider "virtualbox" do |vb|
      vb.memory = "1536"
      end
      e
      config.vm.network "forwarded_port", guest: 8080, host: 8080

    Isso vai mudar a memória da máquina virtual para 1.5GB ( = 1024 MB * 1.5), suficiente para um BA Server 5.x, e vai fazer um forward da porta 8080 da máquina virtual para a máquina real.

  6. Ainda dentro daquele diretório, subi o servidor Vagrant com o comando vagrant up. Na primeira execução ele baixou um disco virtual configurado com Ubuntu Precise Pangolin (12.04 LTS) para 32 bits, e só então subiu o servidor.

Voi-là! Agora temos uma máquina virtual pronta para ser configurada com o BA Server. O que precisamos fazer é bem simples: adicionar Java 1.7, baixar e descompactar o BA Server 5.4 e configurar o servidor para subi-lo automaticamente. Vamos nessa:

  1. Acessamos o servidor Vagrant rodando com o comando vagrant ssh. Um terminal se abre diretamente no servidor virtual;
  2. Vamos instalar o Java Oracle: é só adicionar o repositório e rodar um apt-get:
    1. Dentro do servidor Vagrant comandamos sudo apt-get update para atualizar a lista de pacotes disponíveis;
    2. Para adicionarmos a chave do repositório Java WebUpd8 precisamos de alguns pacotes. Instale-os com este comando:sudo apt-get install python-software-properties;
    3. Depois disso estamos preparados para adicionar a chave do PPA:sudo add-apt-repository ppa:webupd8team/java. Apenas bata enter para concluir;
    4. Atualize os repositórios novamente, com outro sudo apt-get update;
    5. Finalmente, comande a instalação do Java 7:sudo apt-get install oracle-java7-installer;

      A instalação do Java por meio de repositório no Ubuntu é um truque: a licença da Oracle não permite empacotá-lo no repositório, então o que realmente baixamos é um programa de instalação que coleta, por meio de um prompt, uma anuência com os termos legais da Oracle, para então baixar os arquivos do Java e configurá-lo. Por isso a série de pontinhos, indicando o download – uma coisa que não acontece com o apt-get ordinário.


  3. Ao final teste o java: comande java -version e veja se volta uma mensagem informando a versão;
  4. Vamos precisar de outro programa: unzip. Comande sudo apt-get install unzip para instalá-lo;
  5. Instale o BA Server:
    1. Ainda no SSH do Vagrant, entre sudo mkdir /opt/pentaho para criar o diretório no qual vamos deixar o servidor;
    2. Para facilitar nossa vida, mude esse diretório para “casa da mãe joana”, comandando sudo chmod 777 /opt/pentaho. Isso vai dar permissão de escrita geral no diretório pentaho;
    3. Mude para ele, cd /opt/pentaho, e baixe o Pentaho BA Server 5.4 a partir do SourceForge:wget http://bit.ly/29gb4ak --output-document=biserver-ce-5.4.0.1-130.zip
    4. Depois que ele terminar de baixar, descompacte-o: comande unzip biserver-ce-5.4.0.1-130.zip;
    5. Terminou de descompactar? O zip não é mais necessário, e você pode removê-lo com rm biserver-ce-5.4.0.1-130.zip. Não precisa, já que isso não vai forçar o tamanho do disco virtual para baixo automaticamente.

Ufa! Quase lá! Primeiro deixe o BA Server pronto para atuação automática:

cd biserver-ce
./start-pentaho.sh

Responda com enter à mensagem e aguarde alguns minutos. Daí teste abrindo seu navegador web e apontando para http://localhost:8080. Se tudo deu certo você verá a tela de login do servidor. Não se esqueça de baixar o servidor antes de prosseguir, com um ./stop-pentaho.sh dentro da caixa Vagrant.


É importante você rodar o BA Server ao menos uma vez manualmente, e assim se livrar do prompt de execução inicial. Caso contrário o servidor pode não subir na inicialização automática.


E o que falta? Bom, queremos que o servidor Vagrant fique pronto com um único comando – vagrant up – sem precisar de mais nada. Então é necessário configurar o servidor para subir e baixar sozinho, na inicialização da máquina.

Configurando o BA Server para Início Automático

O procedimento descrito aqui foi retirado do capítulo 3 do livro Pentaho na Prática. Você pode baixá-lo [deste link][pnpcap3_bitly], e ter um gosto do livro.

  1. Primeiro, garanta que o servidor Vagrant esteja no ar emitindo o comando vagrant up dentro do diretório em que criamos o arquivo de configuração Vagrant (/home/USUÁRIO/AmbienteVagrant);
  2. Faça login no servidor Vagrant com vagranta ssh;
  3. Assuma credenciais de root na caixa Vagrant: sudo su;
  4. Mude para o diretório de scripts de serviço: cd /etc/init.d;
  5. Abra um editor para um arquivo novo, neste mesmo diretório, chamado biserver-ce: nano biserver-ce (pode usar o vim, se quiser;)
  6. Agora precisamos do script de inicialização de servidor, para Linux. Abra este link em uma outra aba do seu navegador e procure o item “Script de Inicialização do BI Server para Linux”. Baixe este script, abra-o e copie tudo para dentro do arquivo do item anterior. Salve, pressionando CTRL+O e batendo enter, e depois saia do editor, pressionando CTRL+X;
  7. Por fim ative a execução automática: ainda no terminal Vagrant, como sudo, comande: (atenção! são dois blocos diferentes!)
ln -s /etc/init.d/biserver-ce /etc/rc2.d/S99BAServer
ln -s /etc/init.d/biserver-ce /etc/rc3.d/S99BAServer
ln -s /etc/init.d/biserver-ce /etc/rc4.d/S99BAServer
ln -s /etc/init.d/biserver-ce /etc/rc5.d/S99BAServer
 
ln -s /etc/init.d/biserver-ce /etc/rc0.d/K19BAServer
ln -s /etc/init.d/biserver-ce /etc/rc1.d/K19BAServer
ln -s /etc/init.d/biserver-ce /etc/rc6.d/K19BAServer

É isso. Saia de tudo, pare o servidor Vagrant com vagrant halt e depois reinicie-o com vagrant up. Assim que o prompt voltar, abra um navegador web e aponte para http://localhost:8080/pentaho.


O comando vagrant up pode terminar antes de o servidor Pentaho estar no ar. Dê alguns minutos para tudo acabar de acontecer antes de tentar acessar o BA Server com o navegador web.


Conclusão

Acabei de reler tudo, para fazer a conclusão, e acho que devo um pedido de desculpas: parecia mais fácil na minha cabeça… Se você tiver algum problema, ou dúvida, deixe aqui um comentário, que eu te ajudarei.

Vamos lá, para a conclusão.

Virtualização é uma idéia muito legal. Virtualizar máquinas permite desde jogar antigos arcades a testar sistemas operacionais sem precisar arriscar ferrar a nossa máquina e nossos dados.

No mundo dos desenvolvedores, as coisas ficam cada vez mais complicadas. Uma das complicações mais perniciosas é o duo ambiente de desenvolvimento/produção: a tendência humana em mexer agora e documentar depois acaba bagunçando a situação a tal ponto que cada novo deploy, isto é, a cada entrega de uma nova versão no ambiente de produção, exige muito trabalho para compensar as diferenças entre os ambientes.

Para resolver esse problema surgiram tecnologias englobadas na disciplina DevOps, como os provisionadores, softwares que configuram, e forçam essa configuração em um ambiente, automaticamente. Dois membros desta classe são o Puppet e o Chef, que permitem definir uma infraestrutura como se fosse código, tornando possível até mesmo uma coisa estranha: versionar uma infraestrutura, isto é, guardar todas as configurações que ela já teve ao longo do projeto.

Alguém teve a (óbvia e genial) idéia de combinar essas duas coisas e conseguir uma terceira ainda mais bacana: ambientes de desenvolvimento isolados!

O software Vagrant, sobre o qual a Ed. Packt oferece um livro muito bom, faz exatamente isso: permite a criação de ambientes estanques, configurados ao gosto do projeto. Graças a ele, qualquer equipe pode ter um ambiente de desenvolvimento “limpo” (i.e. exclusivo por projeto), uniforme (igual para todo mundo) e estável (não muda sem querer ou por acidente.)

Em um post anterior eu resenhei o livro da Packt sobre o Vagrant, e hoje eu dei aqui o passo-a-passo para montar um servidor Vagrant para projetos que usem o Pentaho BA Server 5.4.

… ou quase: o ideal teria sido definir a configuração como um script Puppet ou Chef (scref?? kkk) e deixar o provisionador tomar conta. Mas eu ainda tenho muito a aprender e por isso resolvi mostrar o que eu já consegui fazer.

Burning Down the House

Eu seguia feliz da vida estudando o Vagrant, quando, de repente! (kkk), fiz o curso da 4Linux sobre DevOps! Foi quando eu fui obrigado a aprender sobre o [Docker][docker_bitly], algo do que eu vinha escapando deliberadamente (infra não é minha praia.) O Docker leva adiante a idéia de isolamento proposta pela virtualização, mas a um custo de infra menor: enquanto que a virtualização quebra uma máquina real em várias virtuais, o Docker monta várias máquinas “virtuais” compartilhando a mesma infra. Isso tem uma grande vantagens logo de saída: por não virtualizar tudo, mas apenas a parte que interessa, ele é muito mais leve e por isso usa melhor os recursos da máquina. De cara a performance de um container Docker é melhor que a de uma máquina virtual.

Há muita coisa ainda para se evoluir e resolver na tecnologia de containers mas, como colocou o The Register, se virtualização é uma tecnologia importante e valiosa em certos cenários, em outros ela é pesada e ineficiente, e coisas como containers são o futuro.

Uma destas coisas, na minha opinião, é justamente a gestão de ambientes, e não apenas de desenvolvimento! Como um container tem performance nativa, podemos montar servidores reais usando Docker e ainda atingir o grau de isolamento e controle proposto pelo Vagrant. No fundo, é a mesma coisa, mas executada de uma forma diferente.

Por isso eu disse, no começo, que “vou mostrar como fazer e, na conclusão, detono tudo. (Tee-he)”: não sei se vou continuar investindo no Vagrant. Ao menos por um tempo, eu definitivamente vou cair de cabeça no mundo do Docker! Eu até comprei um livro da Packt sobre isso, o Learning Docker. Assim que eu acabar de lê-lo vou fazer sua resenha aqui e depois montar o mesmo ambiente de hoje usando Docker.

Docker

Docker

Docker Docker Docker Docker Docker Docker Docker Docker

Já reparou como é viciante falar Docker? Docker Docker Docker Docker

Até a próxima! ;-)

Migrando o Pentaho BA Server +5.x

Até a versão 4.x o Pentaho BI Server usava um repositório que misturava sistema de arquivos com bancos de dados, e era muito prático de mexer. Só tinha um problema: era tosco pra dedéu. A Pentaho aproveitou a reforma geral que deu à luz o BA Server 5.0 e adotou um repositório “profissa”. A partir da versão 5.0 o servidor passou a usar o JackRabbit como repositório oficial.

Eis a definição do projeto pela Apache Foundation, que cuida desse projeto:


O repositório de conteúdo Apache Jackrabbit é uma implementação 100% aderente à API de Repositórios de Conteúdo para Tecnologia Java (JCR especificada nas JSR 170 e JSR 283.)


Logo a seguir dizem que um repositório de conteúdo é “um provedor de armazenamento hierárquivo de conteúdo com suporte para conteúdo estruturado e não-estruturado, busca por texto, versionamento, transações, observação e mais”. Interessante! Será que o repositório do BA Server suporta versionamento? O que é observação? Perguntas para outro post!

Para os usuários do BA Server esse novo formato se traduz em segurança aumentada, mais integração com a plataforma e seus serviços, maior flexibilidade e melhor performance em geral. Uma das mudanças trazidas por esta nova tecnologia é o processo de migração de soluções (do conteúdo gerado no servidor) entre duas versões do BA Server. Antes era só copiar as pastas particulares do diretório ./pentaho-solutions de uma instalação para outra, atualizar o servidor do destino e estava feito.

Ou quase. Na verdade, havia um trabalho meio chato nesse caminho, já que você tinha que levar também as permissões por pasta e objetos e cuidar de alguns outros detalhes. No final das contas, só quem tinha a versão Enterprise (paga) é que tinha um processo de migração mais facilitado.

A adoção do Jackrabbit tornou esse processo de migração mais profissional também para a comunidade. E isso tudo eu escrevi só para dizer que neste post eu vou dividir com vocês o que eu aprendi quando precisei migrar um servidor da série 5.x.


AVISO IMPORTANTE!!!

Mesmo que tenha resolvido meu caso, esse procedimento é experimental!! Estou compartilhando aqui o pouco que eu aprendi para resolver a minha necessidade. Se você decidir aplicá-lo a seu ambiente, o fará por sua conta e risco. Eu não posso ser responsabilizado por nenhuma de suas ações!


Isto posto, terei prazer em ajudar se você tiver algum problema ou dúvida – basta postar um comentário. ;-)

Preparando o Cenário

Para que você aprenda o processo, sem ser atrapalhado por um monte de pequenos detalhes que podem aparecer no caminho, eu sugiro que monte um ambiente simples, no qual você possa testar o processo e praticá-lo à vontade, até aprendê-lo e só então aplicá-lo ao seu ambiente.

Para montar esse ambiente eu sugiro o BA Server 5.4, mas em princípio esse processo deve ser compatível com qualquer versão das séries 5.x e 6.x – mais uma vantagem da adoção de um padrão. Apenas esteja atento para o fato de que o programa que faz a exportação/importação pode ser diferente (pouco ou muito) de uma versão para outra, como, por exemplo, ter um switch a mais ou a menos.

Nosso ambiente terá dois BA Servers, um de origem e outro de destino. Para conseguir isso apenas descompacte o ZIP do BA Server 5.4 para pastas ora com um nome, ora com outro. Neste exemplo o diretório do BA Server de origem chama-se ./biserver-ce e o de destino, ./biserver-ce_DESTINO

Diretório /opt/pentaho/5.4 com dois BA Servers.
Diretório /opt/pentaho/5.4 com dois BA Servers.

Não é possível rodar dois BA Servers simultaneamente sem alterar diversas configurações em pelo menos um deles. Por isso, para manter tudo o mais simples possível e focar só no processo de migração, não vamos rodar os dois ao mesmo tempo, mas apenas um de cada vez: rodamos o de origem, exportamos o repositório, paramos esse servidor, subimos o de destino e importamos o pacote extraído do outro.

Vamos lá!

Exportando o Repositório

Depois de expandir o ZIP do BA Server, suba-o: abra um terminal, mude de diretório e comande ./start-pentaho.sh.


Se você não tem idéia de como fazer isso, bolas, porque está se metendo a migrar a coisa? :-) Mas se você é como eu, que não desiste só porque não está entendendo nada, e quiser experimentar mesmo assim, baixe o capítulo de degustação do meu livro Pentaho na Prática.


Com ele no ar, acesse-o (URL http://localhost:8080/pentaho) com usuário admin e senha password e mude alguma coisa. Apague um arquivo, remova um diretório, criei e salve alguma análise com o jPivot etc. Se você não modificar nada, não vai notar o resultado do processo.

Eu removi todos os usuários, menos o admin, e criei alguns novos. Montei uma visão OLAP com jPivot e salvei em admin. Daí criei uma pasta pública chamada Rodas de Aço e movi para lá todo conteúdo das subpastas do Steel Wheels, apagando esta. No final ficou assim:

Origem: note as pastas de usuários e pública.
Origem: note as pastas de usuários e pública.

Pronto para exportar!

  • O servidor deve estar no ar;
  • Abra um terminal e mude o diretório para dentro do ./biserver-ce de origem;
  • Comande:
./import-export.sh --export --url=http://localhost:8080/pentaho
--username=admin --password=password --file-path=/tmp/Repositorio_54_Origem.zip
--charset=UTF-8 --path=/ --withManifest=true --logfile=/tmp/logfile_export.log

Se tudo der certo a saída no terminal vai ser mais ou menos esta:

fabio@pentaho:~/opt/Pentaho/5.4/biserver-ce_ORIGEM$ ./import-export.sh --export --url=http://localhost:8080/pentaho --username=admin --password=password --file-path=/tmp/Repositorio_54_Origem.zip --charset=UTF-8 --path=/ --withManifest=true --logfile=/tmp/logfile_export.log
WARNING: Using java from path
DEBUG: _PENTAHO_JAVA_HOME=
DEBUG: _PENTAHO_JAVA=java
log4j:WARN Continuable parsing error 3 and column 57
log4j:WARN Document root element "configuration", must match DOCTYPE root "null".
log4j:WARN Continuable parsing error 3 and column 57
log4j:WARN Document is invalid: no grammar found.
log4j:WARN The <configuration> element has been deprecated.
log4j:WARN Use the <log4j:configuration> element instead.
Export Completed
Response Status: 200
Export written to: /tmp/Repositorio_54_Origem.zip
fabio@pentaho:~/opt/Pentaho/5.4/biserver-ce_ORIGEM$

E você terá um zip, na pasta /tmp, contendo o repositório de arquivos do servidor:

Conteúdo do arquivo de backup do repositório.
Conteúdo do arquivo de backup do repositório.

Note que interessante: ainda existem diretórios ocultos, como o famoso /bi-developers, uma coleção de exemplos de uso do BI Server.

E uma “pegadinha”: parece que nenhum dos diretórios de usuários, que estavam vazios, foram exportados. Isso não é verdade, pois eles aparecem se listarmos o conteúdo do arquivo em um terminal (ou talvez com algum outro programa que não o File Roller):

fabio@pentaho:/tmp$ unzip -l Repositorio_54_Origem.zip 
Archive:  Repositorio_54_Origem.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2016-06-29 13:02   home/
        0  2016-06-29 13:02   home/Everton/
        0  2016-06-29 13:02   home/Fabio/
        0  2016-06-29 13:02   home/Joe/
        0  2016-06-29 13:02   home/admin/
     7052  2016-06-29 13:02   home/admin/Analise+jPivot.xjpivot
      186  2016-06-29 13:02   home/admin/Analise+jPivot.xjpivot.locale
       62  2016-06-29 13:02   home/index_pt_BR.locale
        0  2016-06-29 13:02   public/
        0  2016-06-29 13:02   public/bi-developers/
(...)
       84  2016-06-29 13:02   public/index.locale
       64  2016-06-29 13:02   public/index_pt_BR.locale
   961634  2016-06-29 13:02   exportManifest.xml
---------                     -------
 10708536                     2014 files
fabio@pentaho:/tmp$

O comando de exportação para Windows tem apenas as diferenças do sistema operaciona: muda de .sh para .bat e tudo que é / vira c:\ :

import-export.bat --export --url=http://localhost:8080/pentaho
--username=admin --password=password
--file-path=%USERPROFILE%\AppData\Local\Temp\Repositorio_54_Origem.zip
--charset=UTF-8 --path=/ --withManifest=true
--logfile=%USERPROFILE%\AppData\Local\Temp\logfile_export.log

Ao contrário do Linux, que por padrão tem um diretório /tmp universal, no Windows cada usuário tem seu próprio diretório temp. Ele pode ser referenciado pela variável %USERPROFILE%\AppData\Local\Temp, que usamos acima.


Importando o Repositório

Baixe o servidor de origem e suba o de destino. Pronto?

  • O servidor de destino deve estar no ar;
  • Abra um terminal e mude o diretório para dentro do ./biserver-ce de destino;
  • Comande:
./import-export.sh --import --url=http://localhost:8080/pentaho --username=admin
--password=password --charset=UTF-8 --path=/ --file-path=/tmp/Repositorio_54_Origem.zip
--logfile=/tmp/logfile_import.log --permission=true --overwrite=true --retainOwnership=true

Ele vai passar um tempo “pensando” e depois começar a cuspir a saída do processamento:

fabio@pentaho:~/opt/Pentaho/5.4/biserver-ce_DESTINO$ ./import-export.sh --import --url=http://localhost:8080/pentaho --username=admin --password=password --charset=UTF-8 --path=/ --file-path=/tmp/Repositorio_54_Origem.zip --logfile=/tmp/logfile_import.log --permission=true --overwrite=true --retainOwnership=true
WARNING: Using java from path
DEBUG: _PENTAHO_JAVA_HOME=
DEBUG: _PENTAHO_JAVA=java
log4j:WARN Continuable parsing error 3 and column 57
log4j:WARN Document root element "configuration", must match DOCTYPE root "null".
log4j:WARN Continuable parsing error 3 and column 57
log4j:WARN Document is invalid: no grammar found.
log4j:WARN The <configuration> element has been deprecated.
log4j:WARN Use the <log4j:configuration> element instead.
done response = <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Repository Import Log</title>
<style type="text/css">
<!--
body, table {font-family: arial,sans-serif; font-size: x-small;}
th {background: #336699; color: #FFFFFF; text-align: left;}
-->
</style>
</head>
<body bgcolor="#FFFFFF" topmargin="6" leftmargin="6" style="font-family: arial,sans-serif; font-size: x-small">
<hr size="1" noshade>
Log session start time Wed Jun 29 15:00:44 BRT 2016<br>
<br>
<table cellspacing="0" cellpadding="4" border="1" bordercolor="#224466" width="100%">
<tr style="background: #336699; color: #FFFFFF; text-align: left">
<th>Time</th>
<th>Import File</th>
<th>Level</th>
<th>File:Line</th>
<th>Message</th>
</tr>
(...)

Isso vai continuar por mais um monte de linhas, varrendo o arquivo inteiro até o final. As mensagens no final devem ser assim:

(...)
<tr>
<td>06/29/2016 15:01:36</td>
<td title="importFile">/public/Public</td>
<td title="Level">INFO</td>
<td>Log4JRepositoryImportLogger.java:53</td>
<td title="Message">Start File Import</td>
</tr>
 
<tr>
<td>06/29/2016 15:01:36</td>
<td title="importFile">/public/Public</td>
<td title="Level"><font color="#993300"><strong>WARN</strong></font></td>
<td>Log4JRepositoryImportLogger.java:181</td>
<td title="Message">Public</td>
</tr>
 
<tr>
<td>06/29/2016 15:01:36</td>
<td title="importFile">/</td>
<td title="Level">INFO</td>
<td>Log4JRepositoryImportLogger.java:47</td>
<td title="Message">End Import Job</td>
</tr>
</table>
<br>
</body></html>

Na minha contagem, o processo soltou exatas 63636 linhas, incluindo o cabeçalho com mensagens sobre o Java no início – e era um repositório mínimo. :-O

Vamos verificar o resultado? Eis o estado do repositório do servidor de destino antes da importação do backup:

Servidor de destino antes da restauração.
Servidor de destino antes da restauração.

Após fazer a importação usando o import-export.sh temos:

Servidor de destino após a restauração.
Servidor de destino após a restauração.

Observe que não aparece nenhuma das pastas de usuário do servidor de origem, que nós sabemos que existiam no arquivo ZIP, e continuam existindo as pastas que já existiam no destino, ou seja, não foram apagadas.


Volto a frisar: teste o processo algumas vezes para evitar surpresas. Neste exemplo migramos pastas vazias, mas de usuários que não existiam no destino. E se elas não estivessem vazias na origem? Eu fiz o teste: arquivos de diretórios de usuários que não existem no destino, não são importados. Isso é muito importante: arquivos que vêm de diretórios de usuários, na origem, que não existem no destino, são perdidos!! Para funcionar, o usuário precisa existir no destino!


Como Funciona?

É bem simples, na verdade: a Pentaho construiu um programa, import-export.sh (Linux e MacOS) ou import-export.bat (Windows), que chama um “processo” (classe? método?) diretamente no código do servidor. Eis o conteúdo da versão Linux/MacOS (observe a última linha do bloco a seguir:)

#!/bin/sh
DIR_REL=`dirname $0`
cd $DIR_REL
DIR=`pwd`
#cd -
 
. "$DIR/set-pentaho-env.sh"
setPentahoEnv
 
# uses Java 6 classpath wildcards
# quotes required around classpath to prevent shell expansion
"$_PENTAHO_JAVA" -Xmx2048m -XX:MaxPermSize=256m -classpath "$DIR/tomcat/webapps/pentaho/WEB-INF/lib/*" org.pentaho.platform.plugin.services.importexport.CommandLineProcessor ${1+"$@"}

Esse programa possui várias opções e parâmetros. Para ver a lista completa de opções, basta rodar o comando sem nenhum switch:

fabio@pentaho:~/opt/Pentaho/5.4/biserver-ce$ ./import-export.sh
 
(... mensagens de erro por falta de parâmetros ...)
 
usage: importexport
Unified repository command line import/export tool
 -a,--url <arg>                      url of repository (e.g.
                                     http://localhost:8080/pentaho)
 -a_ds,--analysis-datasource <arg>   Analysis datasource description
 -a_xmla,--xmla-enabled <arg>        Analysis XMLA enabled flag
 -c,--charset <arg>                  charset to use for the repository
                                     (characters from external systems
                                     converted to this charset)
 -cat,--catalog <arg>                catalog description
 -ds,--datasource-type <arg>         datasource type
 -e,--export                         export
 -f,--path <arg>                     repository path to which to add
                                     imported files, or to export from
                                     (e.g. /public)
 -fp,--file-path <arg>               Path to directory of files for
                                     import, or path to .zip file for
                                     export
 -h,--help                           print this message
 -i,--import                         import
 -l,--logfile <arg>                  full path and filename of logfile
                                     messages
 -m,--permission <arg>               apply ACL manifest permissions to
                                     files and folders  (import only)
 -m_id,--metadata-domain-id <arg>    Metadata domain ID
 -o,--overwrite <arg>                overwrite files (import only)
 -p,--password <arg>                 repository password
 -params,--params <arg>              parameters to pass to REST service
                                     call
 -r,--retainOwnership <arg>          Retain ownership information  (import
                                     only)
 -res,--resource-type <arg>          Import/Export resource type
 -rest,--rest                        Use the REST (Default) version (not
                                     local to BI Server)
 -u,--username <arg>                 repository username
 -v,--service <arg>                  this is the REST service call e.g.
                                     acl, children, properties
 -w,--withManifest <arg>             Export Manifest ACL file included
                                     (export only)
Common options for import & export using REST ServicesExample arguments
for import:
--import --url=http://localhost:8080/pentaho --username=admin
--password=password --charset=UTF-8 --path=/public
--file-path=c:/temp/steel-wheels
--logfile=c:/temp/logfile.log
--permission=true
" + "--overwrite=true
--retainOwnership=true
Example arguments for export:
--export --url=http://localhost:8080/pentaho --username=admin
--password=password
--file-path=c:/temp/export.zip --charset=UTF-8 --path=/public
--withManifest=true--logfile=c:/temp/logfile.log
Example arguments for running REST services:
--rest --url=http://localhost:8080/pentaho --username=admin
--password=password
-path=/public/pentaho-solutions/steel-wheels/reports
--logfile=c:/temp/logfile.log --service=acl
 
(... Erros por falta de parâmetro ...)
 
fabio@pentaho:~/opt/Pentaho/5.4/biserver-ce$

Então, por exemplo, para exportar apenas o diretório do usuário Joe, usando para isso o usuário admin, que possui todas as permissões de acesso, o comando fica:

./import-export.sh --export --url=http://localhost:8080/pentaho
--username=admin --password=password --file-path=/tmp/PastaDoJoe.zip
--charset=UTF-8 --path=/home/Joe --withManifest=true --logfile=/tmp/logfile_export.log

Note que não exportamos simplesmente “Joe”, mas sim “/home/Joe”. Isso porque a pasta do Joe existe dentro de uma outra subpasta, como você pode observar ao notar o atributo Source nesta figura:

Pasta do Joe no diretório /home.
Pasta do Joe no diretório /home.

E é por isso que usamos --path=/ para exportar/importar o repositório inteiro: / é a raiz de tudo.

O processo de importação segue as mesmas regras, só que no sentido inverso: levando o conteúdo exportado para dentro de um repositório.

Não deixe de consultar o Pentaho Infocenter (ou Pentaho Help) para aprender mais sobre isso:

Curiosamente, a página do BA Server 6 fala que o procedimento exporta tudo, incluindo usuários e permissões, mas não consegui encontrar essa informação no arquivo ZIP. O exportManifest.xml, que registra a lista de pastas e arquivos, e seus respectivos donos e permissões, não mostra nada. E só para tirar a cisma, tentei importar no 6 o repositório do 5, mas o seis não registrou nenhum dos usuários que eu criei no cinco. Pode ser que essas páginas estejam se referindo a alguma ferramenta que vai junto da versão Enterprise (paga), indisponível na Community.

Conclusão

Vimos como usar o programa import-export.sh/bat para exportar o repositório de arquivos de um servidor Pentaho e importar em outro. Depois da substituição do mecanismo de repositório que existia até a versão 4.8, esse método é a única forma de fazer a migração entre dois servidores – uma tarefa necessária quando se instala uma nova versão do Pentaho BA Server e queremos levar tudo que nossos usuários já fizeram.

Mostrei um exercício simples, “migrando” o repositório entre duas instâncias da versão 5.4, para que você possa estudar o processo livre de problemas paralelos. Você pode usar o que aprendeu para experimentar uma migração real, levando os arquivos de uma versão 5.x para a 6.x, por exemplo.

Além disso, ainda é preciso levar os usuários e seus papéis, e todas as conexões de dados, metamodelos e esquemas OLAP. Mesmo assim a nova tecnologia Jackrabbit é mais prática (em especial para a versão CE) que o antigo formato, tosco pra dedéu, de filesystem + banco de dados.

Feliz migrações! ;-)

Configurando PDI para Enviar Relatórios

O Pentaho Data Integration (PDI, antigo Kettle) oferece uma quantidade de opções para se comunicar com o “mundo exterior”. Por exemplo, ele permite envio de e-mails tanto em transformações quanto em jobs por meio de passos nativos, ou mensagens por mensageria instantânea (Instant Messaging, IM) através de plug-ins.

Plug-in PDI que envia notificações a smartphones Apple ou Android.
Plug-in PDI que envia notificações a smartphones Apple ou Android.

Um uso clássico dessa capacidade é o envio de algum tipo de notificação ao final de um processo de ETL. O PDI pode mandar um e-mail para todos os interessados, informando se o processo transcorreu em ordem, ou se houve algum erro, e qual é o estado atual dos dados. Essa transformação faz isso:

Transformação que monta e envia e-mail com relatório para uma lista de destinatários.
Transformação que monta e envia e-mail com relatório para uma lista de destinatários.

Foi exatamente essa transformação que eu usei em um projeto recente, e ela funcionou perfeitamente!… Em desenvolvimento. Em outras palavras, rodava beleza quando eu a testava no Spoon, que é a interface gráfica do PDI, mas falhava fragorosamente ao rodar no ambiente de produção, via linha de comando. Depois de um pouco de tentativa e erro eu consegui resolver todos os problemas, soluções que eu divido com vocês no post de hoje.

Mudança de Ambientes

A primeira dificuldade é o fato de os bancos de dados, seus IPs, usuários e senhas serem diferentes em cada ambiente. Se em desenvolvimento o banco chama-se dw_corp, com usuário e senha postgres, em localhost:5432, em produção sem dúvida será diferente – no mínimo a política de segurança da empresa vai cuidar de ter usuário e senha “protegidos”, i.e., que só o gestor do processo em produção sabe qual é.

Resolvemos essa dificuldade parametrizando toda e qualquer referência ao banco de dados (e por extensão a diretórios, servidores de apoio etc.)

Conexão PDI

Parametrizar uma conexão PDI é simples: basta usar variáveis para registrar os valores de parâmetro de uma conexão. A figura abaixo mostra uma conexão com o banco Beltrano OLTP parametrizada:

Conexão PDI parametrizada.
Conexão PDI parametrizada.

Daí é só registrar essas variáveis e seus valores no arquivo kettle.properties, que fica dentro do diretório .kettle, na raiz do usuário. Seu ambiente de desenvolvimento terá valores para o PDI acessar os seus bancos, enquanto que em produção deve existir um arquivo análogo, configurado adequadamente para esse ambiente, pelo próprio gestor da máquina de produção.

Conexão PRD

Eu queria enviar relatórios bonitos, bem formatados, e não um simples arquivo texto com algumas contagens e por isso eu usei o Pentaho Report Designer. Daí, de cara eu sabia que teria o mesmo problema: valores de conexão diferentes para cada ambiente. Infelizmente, porém, o PRD não pode usar as mesmas variáveis que o PDI usa. Não dá para colocar o mesmo ${BELTRANO_OLTP_HOST} da conexão do PDI no PRD, mas dá para usar uma fonte de dados JNDI, que é um tipo de conexão disponível por meio do ambiente Java.


Eu tive sorte em descobrir como usar JNDI. Nem pense em me perguntar o que é ou como funciona…


Definir uma fonte JNDI no PRD é simples: apenas selecione esse tipo e forneça um nome:

Conexão JNDI no relatório PRD.
Conexão JNDI no relatório PRD.

E onde são registradas os parâmetros de uma conexão JNDI? No arquivo default.properties, dentro do diretório /home/<USUÁRI>/.pentaho/simple-jndi, neste formato:

NomeJNDI/type=javax.sql.DataSource
NomeJNDI/driver=org.postgresql.Driver
NomeJNDI/user=postgres
NomeJNDI/password=postgres
NomeJNDI/url=jdbc:postgresql://EnderecoServidor:5432/NomeDoBanco

Os itens driver e url são particulares de cada banco. O restante é sempre igual.

Parametrizando o PRD no PDI

Com a parametrização do PDI e do PRD eu conseguia montar e rodar processos e relatórios nos dois ambientes sem me preocupar com mais nada, desde que cada um rodasse independentemente do outro. Ou seja, uma transformação executada pelo PDI, e um relatório pelo PRD – no máximo dentro do servidor Pentaho.

Mas eu queria rodar o relatório a partir do PDI!

O primeiro obstáculo foi fácil: onde eu definiria a conexão JNDI do PDI, que – pela simples definição de JNDI – seria repassada a um PRD disparado a partir do PDI? No arquivo jdbc.properties, na pasta ./data-integration/simple-jndi. Basta copiar para ali a definição do outro default.properties, e lembrar de fazer a mesma coisa no ambiente de produção.

Parametrizando o Parametrizador

Ah, se fosse tudo tão lógico e simples!

Foi aqui que a porca torceu o rabo: em desenvolvimento, na interfave gráfica, todas as variáveis eram “vistas” pelo Spoon por default – todas as definições JNDI, por exemplo. Mas ao tentar rodar em produção apareceu uma mensagem nada a ver…

INFO 15-07 09:13:31,507 - Beltrano JNDI Postgres - New database connection defined
ERROR 15-07 09:13:31,534 - Count incomplete revisions - An error occurred, processing will be stopped:
Error occured while trying to connect to the database
java.io.File parameter must be a directory. [/home/users/kettle/CLIENT/simple-jndi]

Depois de cavocar o Google um pouco, eu descobri que, a partir da versão 4.1, o PDI passou a aceitar que o arquivo com as definições JNDI ficasse em qualquer lugar, e não apenas dentro do ./data-integration.

Trecho que chama o Java, dentro dos scripts. Note a variável -DKETTLE_JNDI_ROOT.
Trecho que chama o Java, dentro dos scripts. Note a variável -DKETTLE_JNDI_ROOT.

Para complicar a vida do desenvolvedor, o Spoon preenche essa variável automaticamente, apontando diretamente para o diretório que contém o arquivo de definições, mas o Kitchen e o Pan, não!

Essa modificação precisa ser feita pelo gestor do ambiente de ETL. Para definir a localização do arquivo de propriedades JNDI basta alterar a variável -DKETTLE_JNDI_ROOT,que é definida no final da chamada do Kitchen ou Pan (e até mesmo do Spoon, mas lembre-se que o Spoon faz coisa a mais), setando-o uma linha antes da chamada ao Java, desta forma:

KETTLE_JNDI_ROOT=/opt/pentaho/5.1/data-integration/simple-jndi

Note que eu apontei a variável para o meu diretório-padrão. Você deve inserir o diretório correto para sua instalação, não apenas copiar o exemplo acima, cegamente.

Pronto! Finalmente o PRD passou a rodar, parametrizado, dentro do PDI, tanto em desenvolvimento quanto em produção!


Veja este post no fórum internacional, aqui reproduzido parcialmente para o caso de ter sumido=.)*

Post do fórum Pentaho no qual é solucionado esse problema.
Post do fórum Pentaho no qual é solucionado esse problema.

Conclusão

Uma das eternas promessas da TI é oferecer gestão por exceção. Nesta modalidade, os gestores de alguma coisa são notificados quando esta alguma coisa assume um estado inadequado. Por exemplo, quando os valores de indicadores caem fora de certas faixas, ou quando um erro surge em algum sistema. Na gestão por exceção, o sistema não dá um pio enquanto tudo estiver certo, e dispara notificações quando as coisas saem dos trihos.

Ferramentas de ETL também carregam essa promessa. Dependendo do marketing, ora vende-se a idéia de avisar o gestor do processo de ETL tão cedo ocorra um erro, ou notificar os clientes que os dados foram carregados e estão pronto.

O PDI pode executar a tal gestão por exceção: basta incutir-lhe a lógica de notificação e os mecanismos de comunicação adequada. Como vimos neste post, dá para desenhar um relatório de alta qualidade, renderizá-lo em PDF e transmiti-lo por e-mail para um ou mais destinatários, sempre que uma condição desejada é atingida.

Colocar isso tudo para rodar, porém, são outros quinhentos. Neste post vimos como parametrizar tanto o relatório PRD quanto os artefatos PDI para garantir que o processo funcionará em desenvolvimento e em produção.

Até a próxima!

Analisando os Logs do PDI – Parte 3

No primeiro post da série vimos como configurar a captura de logs nos processos do PDI, e obter informações básicas sobre os resultados de um processo qualquer.

No segundo post eu mostrei como usar os dados de performance de uma transformação para “caçar” gargalos.

Na terceira e última parte vamos entender como usar as tabelas logging channel para montar um relatório que lista todas as transformações e jobs executados a partir de um job-pai.

Cenário

Eis um exemplo básico de ETL que carrega um Data Warehouse dimensional:

Job principal de refresh do DW Beltrano.
Job principal de refresh do DW Beltrano.

O job acima chama uma transformação que, como o nome diz, define as variáveis do processo, e depois segue chamando os subjobs, cada um com uma tarefa específica: atualizar dimensões, carregar fatos e por fim preencher as tabelas pré-agregadas para OLAP. Por último é chamada outra transformação que coleta informações sobre o estado do DW naquele dia.

Dentro de cada um daqueles subjobs temos uma sequência de transformações, como, por exemplo, a carga das dimensões:

Job de sequenciamento de carga das dimensões.
Job de sequenciamento de carga das dimensões.

E cada uma dessas transformações faz a real movimentação de dados:

Carga da dimensão Cliente.
Carga da dimensão Cliente.

Para sabermos se tudo funcionou precisamos consultar o log de cada uma delas. Como os jobs estão amarrados com avanços condicionais (setas verdes), se der algum problema, o processo inteiro é abortado. Isso dá alguma facilidade de monitoração. Rodando no Spoon, o erro fica aparente:

Problema no processamento das dimensões.
Problema no processamento das dimensões.

Só que em produção não temos Spoon, então precisamos examinar o log:

2016/03/19 10:44:20 - Spoon - Starting job...
2016/03/19 10:44:20 - Refresh DW Beltrano - Start of job execution
2016/03/19 10:44:20 - Refresh DW Beltrano - Starting entry [Seta Variáveis]
2016/03/19 10:44:20 - Seta Variáveis - Loading transformation from XML file [file:///home/beltrano/ETL_Beltrano/t_a_seta_variaveis.ktr]
2016/03/19 10:44:20 - BELTRANO - KTR - Seta Variáveis - Dispatching started for transformation [BELTRANO - KTR - Seta Variáveis]
2016/03/19 10:44:20 - Grava timestamp.0 - Connected to database [beltrano_dw] (commit=1000)
2016/03/19 10:44:20 - Recupera Timestamp do Refresh.0 - Finished processing (I=0, O=0, R=1, W=2, U=0, E=0)
2016/03/19 10:44:20 - Seta variável.0 - Setting environment variables...
2016/03/19 10:44:20 - Seta variável.0 - Set variable REFRESH_TIMESTAMP to value [2016/03/19 10:44:20.724]
2016/03/19 10:44:20 - Seta variável.0 - Finished after 1 rows.
2016/03/19 10:44:20 - Seta variável.0 - Finished processing (I=0, O=0, R=1, W=1, U=0, E=0)
2016/03/19 10:44:20 - Grava timestamp.0 - Finished processing (I=0, O=1, R=1, W=1, U=0, E=0)
2016/03/19 10:44:20 - Refresh DW Beltrano - Starting entry [Carga das Dimensões]
2016/03/19 10:44:20 - Refresh DW Beltrano - Carga das Dimensões - Starting entry [Dimensão Clientes]
2016/03/19 10:44:20 - Dimensão Clientes - Loading transformation from XML file [file:///home/beltrano/ETL_Beltrano/t_d_clientes.ktr]
2016/03/19 10:44:20 - Dimensão Clientes - Dispatching started for transformation [Dimensão Clientes]
2016/03/19 10:44:21 - Lê CNPJs.0 - Finished reading query, closing connection.
2016/03/19 10:44:21 - Lê CNPJs.0 - Finished processing (I=5000, O=0, R=0, W=5000, U=0, E=0)
2016/03/19 10:44:21 - Insere Tipo.0 - Finished processing (I=0, O=0, R=5000, W=5000, U=0, E=0)
2016/03/19 10:44:21 - Formata fluxo PJ.0 - Finished processing (I=0, O=0, R=5000, W=5000, U=0, E=0)
2016/03/19 10:44:21 - Lê CPFs.0 - Finished reading query, closing connection.
2016/03/19 10:44:21 - Lê CPFs.0 - Finished processing (I=50000, O=0, R=0, W=50000, U=0, E=0)
2016/03/19 10:44:21 - Insere Tipo e Cargo.0 - Finished processing (I=0, O=0, R=50000, W=50000, U=0, E=0)
2016/03/19 10:44:21 - Formata fluxo PF.0 - Finished processing (I=0, O=0, R=50000, W=50000, U=0, E=0)
2016/03/19 10:44:21 - Une fluxos.0 - Finished processing (I=0, O=0, R=55000, W=55000, U=0, E=0)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - ERROR (version 5.4.0.0-128, build 1 from 2015-06-03_13-41-59 by buildguy) : Unexpected error
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - ERROR (version 5.4.0.0-128, build 1 from 2015-06-03_13-41-59 by buildguy) : org.pentaho.di.core.exception.KettleDatabaseException: 
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - An error occurred executing SQL: 
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - SELECT count(*) FROM d_clientes WHERE cliente_sk = 0
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - ERROR: relation "d_clientes" does not exist
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -   Position: 22
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - 
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.openQuery(Database.java:1722)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.openQuery(Database.java:1652)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.openQuery(Database.java:1648)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.openQuery(Database.java:1635)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.getOneRow(Database.java:2963)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.trans.steps.dimensionlookup.DimensionLookup.checkDimZero(DimensionLookup.java:1681)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.trans.steps.dimensionlookup.DimensionLookup.processRow(DimensionLookup.java:216)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.trans.step.RunThread.run(RunThread.java:62)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at java.lang.Thread.run(Thread.java:745)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - Caused by: org.postgresql.util.PSQLException: ERROR: relation "d_clientes" does not exist
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -   Position: 22
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:405)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:285)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     at org.pentaho.di.core.database.Database.openQuery(Database.java:1711)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 -     ... 8 more
2016/03/19 10:44:21 - Ordena lista.0 - Finished processing (I=0, O=0, R=55000, W=15882, U=0, E=0)
2016/03/19 10:44:21 - Dimensão Clientes - ERROR (version 5.4.0.0-128, build 1 from 2015-06-03_13-41-59 by buildguy) : Errors detected!
2016/03/19 10:44:21 - Estado.0 - Finished processing (I=28, O=0, R=6154, W=6154, U=0, E=0)
2016/03/19 10:44:21 - Carrega Dimensão Clientes.0 - Finished processing (I=0, O=0, R=1, W=0, U=0, E=1)
2016/03/19 10:44:21 - Dimensão Clientes - Transformation detected one or more steps with errors.
2016/03/19 10:44:21 - Dimensão Clientes - Transformation is killing the other steps!
2016/03/19 10:44:21 - Cidade.0 - Finished processing (I=9715, O=0, R=8553, W=8552, U=0, E=0)
2016/03/19 10:44:21 - Dimensão Clientes - ERROR (version 5.4.0.0-128, build 1 from 2015-06-03_13-41-59 by buildguy) : Errors detected!
2016/03/19 10:44:21 - Refresh DW Beltrano - Carga das Dimensões - Finished job entry [Dimensão Clientes] (result=[false])
2016/03/19 10:44:21 - Refresh DW Beltrano - Finished job entry [Carga das Dimensões] (result=[false])
2016/03/19 10:44:21 - Refresh DW Beltrano - Finished job entry [Seta Variáveis] (result=[false])
2016/03/19 10:44:21 - Refresh DW Beltrano - Job execution finished
2016/03/19 10:44:21 - Spoon - Job has ended.

Lendo o log descobrimos, facilmente, que o problema é a tabela d_clientes, que não foi criada no DW.

“Facilmente”?

Talvez em um processo simples, com poucos passos – e quando o erro aparece logo no começo. Mas achar o erro em um log desses, que pode chegar a vários megabytes, é qualquer coisa, menos “fácil”.

Você pode argumentar que basta fazer uma busca por ERROR. Verdade, mas precisaria fazer a busca no log inteiro, até o fim! E depois outra: onde é que apareceu mesmo esse erro? Examine o log outra vez: depois que achar o erro, você precisa seguir o log para cima, para descobrir em que arquivo (job ou transformação) ele ocorreu, ou para baixo, até encontrar o nome do job/transformação – mas não o nome do arquivo!

Resumindo: dá para fazer, mas é um porre.

Encontrando Nemo. Digo, Erros!

Eu sempre digo que sou um cara prático (preguiçoso é feio, ainda que seja mais franco, hehe) e gosto de usar computadores para fazer qualquer tarefa que possa ser feita por eles.

Uma forma mais fácil de encontrar erros é montar uma consulta como a do primeiro artigo e listar tudo que possuir o campo status igual a stop:

 (SELECT
       id_job,
       'Job' as tipo,
       jobname as nome,
       status,
       to_char(replaydate, 'DD/MM/YY HH24:MI:SS') as replaydate
  FROM job
  WHERE status='stop')
UNION
  (SELECT
       id_batch,
       'Transformação' as tipo,
       transname as nome,
       status,
       to_char(replaydate, 'DD/MM/YY HH24:MI:SS') as replaydate
  FROM transformation
  WHERE status='stop')
ORDER BY replaydate,nome

Resultado:

id tipo nome status replaydate
3 Job Popula Empresa-Case stop 23/02/16 20:48
8 Job Empresa-Case – Popula Tabelas Indepentes stop 23/02/16 20:55
2037 Transformação BELTRANO – KTR – Seta Variáveis stop 19/03/16 10:32
2039 Transformação Dimensão Clientes stop 19/03/16 10:33
2041 Transformação Dimensão Clientes stop 19/03/16 10:35
2043 Transformação Dimensão Clientes stop 19/03/16 10:44

Bem melhor, não? O problema aqui é que ele traz todo mundo. Ainda precisaríamos fazer algum filtro para pegar só o do dia anterior, ou até uma semana para trás, ou algo assim.

Mas podemos fazer melhor.

16.3 Árvore Genea-LOG-ica

Segundo Matt Casters, a tabela de logging channels surgiu como uma forma de amarrar os diversos logs: todas as coisas que são geradas no PDI ganham um ID particular, que é usado sempre que precisam – internamento ou no registro de log – se referir à aquele objeto. (Pelo menos foi o que eu entendi.) Isso é uma evolução em relação ao sistema antigo, que usava um ID sequencial para cada item, o que, convenhamos, é algo um tanto quanto noob.

O sistema de logs do PDI grava os canais de log em um tabela com o seguinte layout:

Coluna Tipo Descrição
id_batch int4 ID do lote
channel_id varchar ID do canal
log_date timestamp Data de registro nesta tabela
logging_object_type varchar Tipo do objeto: job, stransformação, banco de dados etc.
object_name varchar Nome do objeto
object_copy varchar Número da cópia do objeto
repository_directory varchar Caminho do objeto (repositório em banco)
filename varchar Diretório e nome do arquivo que contém este objeto
object_id varchar ID do objeto no repositório (repositório em banco)
object_revision varchar Versão do objeto (só para versão EE)
parent_channel_id varchar ID do canal do objeto-pai, que criou este objeto
root_channel_id varchar ID do canal do objeto-ancestral, que deu origem a todos os outros

O PDI pode salvar jobs e transformações em um sistema de arquivos, como um arquivo XML, ou em um repositório em banco de dados. As colunas da tabela que se referem a atributos válidos apenas para artefatos gravados no repositório em banco de dados recebem nulo quando o job ou transformação é gravado como um arquivo ordinário.


Pelo fato de os IDs serem gerados como um hash, o risco de colisão é próximo de nulo. Tanto é assim que as tabelas para canais de job e transformação tem o mesmo layout, e a Pentaho recomenda usar uma só tabela para registrar os dois.

Eis o conteúdo de algumas destas colunas:

Algumas colunas da tabela logging Channels.
Algumas colunas da tabela logging Channels.

Podemos usar essa tabela para listar todos os jobs e transformações envolvidos em um único processo. Depois, usando as tabelas de log de job e transformação, podemos adicionar o status e ordená-los pela data e hora de inicialização (replaydate.) Podemos montar um relatório com esse resultado. Daí poderemos revisar o processamento do dia e encontrar eventuais falhas muito mais – agora sim! – facilmente.

Vamos fazer isso, então.

Lista de Jobs-Raiz

Um job-raiz, por falta de um termo melhor, é um job que está na raiz de um processamento qualquer, e corresponde à lista de todos os tipos de objeto (coluna logging_object_type) JOB, cujo pai é nulo e que as tem a coluna root_channel_id igual à channel_id. Por exemplo, na figura anterior, o último job do ID_BATCH igual à 1023 é um job-raiz.

A consulta que traz isso é:

SELECT id_batch,
       channel_id,
       log_date,
       object_name
FROM job_logging_channels
WHERE logging_object_type = 'JOB'
      AND parent_channel_id IS NULL
      AND channel_id = root_channel_id

E eis o resultado:

id_batch channel_id log_date object_name
18 f411e0d2-… 2016-02-23 21:45:12.588 Popula Empresa-Case
22 9e142006-… 2016-02-23 22:27:00.323 Popula Tabelas de Pedidos
1023 b604142b-… 2016-03-19 10:27:20.576 Refresh DW Beltrano

Essa lista é o primeiro filtro do relatório: o conteúdo da coluna object_name será apresentado ao usuário como um prompt. E como cada job pode ter sido executado diversas vezes, um segundo prompt vai apresentar a lista de datas em que aquele processo foi executado, para que o usuário escolha que corrida analisar.

A lista de datas de execução é obtida com uma consulta na tabela de log do job, filtrada pelo object_name. Usando o job Popula Empresa-Case como exemplo, a lista de datas vem desta consulta:

SELECT DISTINCT
       channel_id,
       replaydate
FROM job
WHERE jobname = 'Popula Empresa-Case'

Usando essas consultas eu comecei o relatório:

Relatório de linhagem do job, com prompts de job e corrida.
Relatório de linhagem do job, com prompts de job e corrida.

Lista de Descendentes

A forma como a tabela de canais foi bolada permite construir uma consulta recursiva, para recuperar todas as partes de um processo, descendo até o último nível. Essa é a forma correta de consultar essa tabela. Porém, como eu não sei tanto SQL para poder construir uma consulta recursiva, vou apenas ser criativo e fazer de outra forma.

Os descendentes daquele job-raiz tem todos uma coisa em comum: o mesmo job-raiz (duhn.) Logo, podemos selecionar todos os elementos – jobs e transformações – que foram executados no mesmo pacote fazendo outra consutla à tabela de log. Eis como selecionar somente os jobs e transformações disparados pelo job principal:

SELECT channel_id,
       logging_object_type,
       object_name
FROM job_logging_channels
WHERE logging_object_type IN ('JOB','TRANS')
      AND root_channel_id = ${job_raiz}

O resultado, especificamente para o caso do job-raiz 9e142006-fb5d-4b28-8b87-1ff0c706919e, é:

channel_id logging_object_type object_name
d4d5227e-c07b-45d1-a6a9-715310de2e7e TRANS Gera Pedidos
56639da7-cb6d-435f-8d1e-c3a1f99c8687 TRANS Gera Parâmetros para Itens de Pedidos
06af3232-75ea-4b7f-b178-eab915e190df TRANS Seta Variáveis de Subitens
ee44ed8d-dbcc-431b-9b9d-d8220fe78838 TRANS Gera Pedidos Detalhes
aa0a4992-be94-4f8e-b0bf-98d14c0baaef JOB Popula Itens de Pedidos
957dc288-16e1-462c-9f1a-89efb026a2a2 TRANS Seta Variáveis de Subitens
4f2927bf-14c5-4b5a-a0d3-8a4c8eb597d7 TRANS Gera Pedidos Detalhes
a4dbea3e-6731-4fc3-92fb-1230888847d9 TRANS Seta Variáveis de Subitens
095dd255-20ec-4b96-a1d5-cf3a316f248d TRANS Gera Pedidos Detalhes
9e142006-fb5d-4b28-8b87-1ff0c706919e JOB Popula Tabelas de Pedidos

Pronto! Temos a nossa lista de jobs e transformações que compõe o job principal! Agora precisamos apenas dos detalhes de cada um deles, que estão nas respectivas tabelas de log de job e de transformação.

Detalhando a Lista

Como os detalhes de jobs e transformações estão em tabelas separadas, vamos fazer dois JOINs e depois reuni-los. Primeiro, os detalhes dos jobs:

SELECT logging_object_type,
       object_name,
       status,
       replaydate
FROM job_logging_channels, job
WHERE logging_object_type = 'JOB'
      AND job_logging_channels.channel_id = job.channel_id
      AND root_channel_id = ${job_raiz}

E agora os das transformações:

SELECT logging_object_type,
       object_name,
       status,
       replaydate
FROM job_logging_channels, transformation
WHERE logging_object_type = 'TRANS'
      AND job_logging_channels.channel_id = transformation.channel_id
      AND root_channel_id = ${job_raiz}

Unindo as duas consultas, temos o resultado completo:

Relatório completo, mostrando a linhagem de execução, ordenada por data/hora.
Relatório completo, mostrando a linhagem de execução, ordenada por data/hora.

Conclusão & Encerramento

O Pentaho Data Integration é uma das mais modernas e sofisticadas ferramentas de integração de dados disponíveis. Entre seus vários recursos estão a captura de logs muito detalhados, dos quais podemos extrair um gama de informaçôes sobre os processos executados por ele.

Nesta série vimos como configurar e usar o sistema de logs do PDI para obter uma visão simples, ainda que minimamente completa, sobre o que se passou em uma dada corrida (primeiro post).

No segundo post vimos como analisar os logs das transformações para detectar os gargalos, isto é, os pontos que puxam a velocidade da dita transformação para baixo.

Com este terceiro post concluímos a série. Vimos como usar um recurso fundamental do sistema de logs, a tabela de “canais” de log (logging channels), para montar uma listagem que sequencia todos os jobs e transformações executados em um processo (clique aqui para baixar o relatório.)

Esses três artigos formam um exemplo simples e prático para monitorar o processo diário, mas há muito que podemos fazer para melhorar a gestão de um DW. Por exemplo, temos todas as possibilidades de automação de detecção de erros e acionamentos por e-mail.

Até a próxima. ;-)

Diferença Entre SAS e MicroStrategy

Sempre que alguém chega ao blog por meio de uma busca na web, o WordPress.com registra o termo que resultou nesta busca. Ontem, por exemplo, estava lá o seguinte:

Top Searches

dw dimensão data semana exemplo,
livro como criar datawarehouse,
diferença entre sas e microstrategy,
controle de chaves planilha

Ora, pensei eu, diferença entre o SAS e o MicroStrategy? Por quê não? Semana que vem eu trarei a última parte da série Logs do PDI, com a consulta que dá a árvore de jobs e transformações. Hoje eu vou comentar sobre sobre como se comparam essas ferramentas.

Ferramentas & BI

Quem acompanha o blog sabe que eu tenho uma queda, um tombaço, por conceitos. Sou Físico, adoro teoria, não posso fazer nada.

Mas,por mais que eu reforce a importância dos conceitos para resolver um problema da melhor forma possível, no final do dia são as ferramentas que materializam os resultados. Tão importante quanto conhecer a teoria é saber quais são as ferramentas, como elas funcionam e como se relacionam aos conceitos.

O post de hoje vai começar explicando o básico da diferença entre MicroStrategy e SAS, e depois vai classificar as ferramentas mais famosas em categorias mais ou menos óbvias. A intenção não é chover no molhado, mas ser um recurso simples e rápido a quem tem pressa de entender essas diferenças.

A minha definição de BI é “a aplicação do método científico aos dados de uma empresa”. Para que isso aconteça precisamos preparar os dados e depois explorá-los. Ou seja, grosso modo, há duas grandes atividades em BI:

  • Juntar dados;
  • Analisar dados.

Portanto, essas são as duas grandes categorias de divisão de ferramentas em BI.


O MicroStrategy pertence exclusivamente à segunda categoria, análise de dados. O SAS pertence a ambas categorias: ele serve para acumular e analisar os dados.


O MicroStrategy

Se você examinar a página da plataforma MicroStrategy, vai notar que, logo no começo, há os seguintes dizeres:

With out-of-the-box gateways and native drivers, MicroStrategy makes it easy to seamlessly connect to any enterprise resource, including databases, mobile device management (MDM) systems, enterprise directories, cloud applications, physical access control systems, and more.

Traduzindo livremente:

Com conectores prontos e drivers nativos, o MicroStrategy facilmente conecta-se a qualquer recurso corporativo, incluindo bancos de dados, sistemas de gerenciamento de dispositivos móveis (MDM), diretórios corporativos, aplicações em nuvem, sistemas de controle de acesso físico e mais.

Se você seguir o link para saber mais, vai ver a mesma mensagem, apenas com outras palavras.

Apesar de eles até comentarem sobre dados e tal, no fundo o MicroStrategy não mexe com os dados de origem. O que o MicroStrategy faz, e faz muito bem por sinal, é servir um monte de tipos de visualização de dados, em um monte de meios diferentes, a partir de um monte de fontes de dados. Ele faz praticamente tudo que existe para ser feito em termos de visualização, exploração de dados e distribuição de resultados. Mas o MicroStrategy não integra dados e não faz Data Mining.

O SAS

O SAS é uma suite composta pelo Sistema SAS e diversos produtos periféricos. O SAS entrega tudo que o MicroStrategy entrega, com um pouco menos de “ooohhhh”, claro, e ainda faz integração de dados e Data Mining.

SAS significa Statistical Analysis System, e foi desenvolvido para atender uma necessidade do governo dos EUA. Seguindo a fantástica tradição norte-americana de unir Ciências e Negócios, esse software acadêmico cresceu e virou um produto de sucesso. Por mais de quarenta anos ele tem evoluído e, hoje, SAS é “A” empresa de BI, e a suite SAS é “O” software de BI, contra o qual o mercado inteiro é medido. (Não que o mercado saiba disso, claro. ;-) Não adianta – eu sou fã do SAS.)

O SAS possui um produto para ETL, um para limpeza de dados, um para Data Mining, um para OLAP, um cliente OLAP, ferramentas de relatório, de painéis (afff…), um para etc. etc. etc….

A página de produtos, para você ter uma idéia, lista as coisas por ordem alfabética. Para não soterrar o interessado em specs sheets sem fim, eles também oferecem uma página de soluções, organizada por indústrias – 23 atualmente.

O SAS é muito mais que só uma ferramenta disso ou daquilo. Ele é um software capacitado a implementar e executar a estratégia de BI de empresas de qualquer porte ou setor. Essa é sua força e sua fraqueza – já já veremos porque.

Laranjas e Maçãs

Trocando em miúdos, SAS e MicroStrategy não se comparam diretamente. Assim como SAS e Informatica, SAS e SPSS. Porém podemos comparar:

Não é fácil comparar os produtos do SAS com os outros. Eu já não mexo no SAS há uma década, e não posso afirmar nada hoje. Porém, na comparação direta, na cara do cliente, o SAS tinha uma dificuldade grande em lidar com a concorrência porque cada fornecedor estava em um nicho, mas o SAS estava em todos. A idéia do SAS é vender soluções, que levam o cliente a ganhar dinheiro. Quando o cliente não quer saber de solução, mas precisa apenas comprar uma ferramenta de visualização de dados, o SAS perde parte do seu apelo de plataforma integrada e tal. Perdi várias vendas para o MicroStrategy, simplesmente porque ele era mais fácil de usar e mais bonito. Mas também nunca perdemos uma venda de solução, na qual resolvíamos um problema do cliente – coisas “banais” como estancar a perda de um milhão de clientes por mês, ou otimizar mala-direta de milhões de dólares por campanha. ;-) Nada de relatório ou painel.

Tudo Vs. Tudo

De maneira geral, as ferramentas do mercado atual classificam-se nestas categorias:

  • Integração de Dados:
    • SAS Data Management;
    • Informatica PowerCenter;
    • Pentaho Data Integration;
    • Microsoft Data Integration Services
    • Clover ETL
    • Talend
  • Data Stores
    • Oracle, MS SQL Server, Postgres, MySQL
    • Teradata, Vertica, MoneDB
    • MS SQL Server Analysis Services
    • Hadoop
  • Data Mining
    • SAS Enterprise Miner
    • SPSS
    • RapidMiner
    • R, Weka
  • Visualização
    • SAS Visual Studio, SAS/GRAPH, SAS/OR, SAS/etc…
    • MicroStrategy
    • BO (agora da SAP)
    • Pentaho OLAP, Relatório, Relatório AdHoc e painéis
    • QlikView
    • Tableau

Há um mundaréu de produtos e eu, com certeza, deixei vários de fora. A idéia, como eu disse no início, é só dar uma base para consulta rápida, que te mostre ao menos o caminho, a direção na qual seguir para estudar mais.


Repare que o SAS e o Pentaho aparecem em todas as categorias (Weka é parte do Pentaho), exceto Data Store. Isso é uma feliz coincidência: o Pentaho é, no fundo, um SAS open source.


Concluindo…

…uma comparação minuciosas entre quaisquer produtos do mercado de BI tende a ser muito complicada. Vários produtos possuem similaridades que justifiquem colocá-los como concorrentes, mas nem sempre dá para fazer uma comparação 1 para 1. Na verdade, raramente dá. Se você precisa se decidir entre um produto e outro, tente pelo menos levar em consideração a estratégia da empresa e o futuro que vocês planejam.

Até a próxima. ;-)

Relatórios com Metamodelos – Complemento

Semana passada eu mostrei como montar um relatatório a partir de um metamodelo. Hoje eu vou encerrar o assunto com mais algumas dicas.

Concepts

Um dos pilares de um bom relatório é a qualidade da apresentação, e nesta qualidade inclui-se a consistência, ou seja, dados do mesmo tipo possuem a mesma aparência, ou no mínimo possuem algum padrão.

Um relatório ordinário, construído a partir de um SQL, tem seus campos formatados livremente. Se por um lado isso é bom, já que dá espaço irrestrito para o autor do relatório passar sua mensagem, por outra é ruim, porque obriga esse mesmo autor a uma formatação tediosa, repetitiva. Fora o aborrecimento de repetir sempre a mesma coisa, ainda podemos acabar esquecendo ou mudando algum detalhe ao longo do tempo.

Um concept, ou conceito, é um padrão de formatação definido dentro do metamodelo e obedecido integralmente pelo PRD. Acesse esta página para obter mais informações sobre concepts.

Vamos fazer um exercício: criaremos um conceito de texto destacado e aplicaremos ao relatório do post anterior. Primeiro, abrimos o PME e carregamos o metamodelo do Beltrano OLTP. Em seguida acessamos o editor de conceitos (concept editor):

Acessando editor de conceitos no PME.
Acessando editor de conceitos no PME.

Nele clicamos sobre o conceito Base e depois clicamos no sinal de + no canto superior direito dessa seção. Uma janela se abrirá, pedindo o nome do conceito – eu eu chamei de Destaque. Como criamos o novo conceito a partir do Base, Destaque herdou as propriedades deste. Caso contrário, se tívéssemos criado um conceito na raiz, ele teria nascido vazio e precisaria receber todos os atributos prentendidos.

Com o conceito Destaque selecionado, clique no elo ao lado do atributo Color of Text. Isso quebra a herança e nos permite redefinir aquele atributo, mantendo o restante:

Novo conceito: destaque (fonte em cor vermelha).
Novo conceito: destaque (fonte em cor vermelha).

Dê ok e, de volta à interface principal do PME, localize um campo na camada de apresentação – Neste exemplo eu selecionei Autor. Clique com o botão da direita sobre ele e selecione Set Parent Concept… para escolher o conceito desejado. Selecione Destaque na janela que se abrirá e Ok para aplicar.

Atribuindo conceito a campo Autor.
Atribuindo conceito a campo Autor.

Feito! Quando o campo Autor for usado no relatório, ele aparecerá em cor vermelha, em destaque:

Conceito entra em ação automaticamente.
Conceito entra em ação automaticamente.

Notou a festa do caqui que está o layout do relatório, na parte de cima da figura? Mas como o PRD vai respeitar o definido no metamodelo, o relatório vai sair arrumadinho, apenas com o nome do autor em vermelho!

Outro exemplo: digamos que precisamos formatar a coluna da direita como um valor monetário, usando a máscara R$ #.###,00. Alteramos ou criamos um conceito no metamodelo, exportamos e reaplicamos o metamodelo à consulta previamente criada:

Altere um conceito para alterar o relatório.
Altere um conceito para alterar o relatório.

Reaplicar o metamodelo a um relatório aberto no PRD é meio chato. Como o PRD não embute o metamodelo no relatório, bastaria purgar o cache ou fechar o relatório e recarregá-lo para forçar o PRD a reler o XMI. Por puro e simples hábito, eu apelo para força bruta: simplesmente apago e recrio a fonte e as consultas (apelando para um copy-paste básico, já que ninguém é de ferro…)

Para relatórios publicados no BA Server não é preciso nada: basta republicar o modelo a partir do PME, ou recarregá-lo no quadro Manage Data Sources e já está valendo. A série 5 do BA Server veio com purga e recarga automática de metamodelos na republicação.


Só essa simplicidade e praticidade, na minha opinião, já é o bastante para fazer valer a pena usar um MQL ao invés de SQL.

Prompts

Um recurso crucial para relatórios são os “prompts”, ou filtros, que permitem ao usuário escolher uma determinada fatia dos dados para apresentação. O PRD oferece esse recurso sob o nome de parameters. Um parameter – ou prompt – é uma variável preenchida pelo usuário em tempo de execução, que entra na consulta como algum tipo de restrição. Por exemplo, a consulta abaixo retorna todos os clientes de um determinado “tipo”, filtrando a consulta pelo conteúdo do prompt tipo_selecionado:

    SELECT cliente, estado, cidade
    WHERE tipo = ${tipo_selecionado}

Não é um mecanismo complicado, mas não é trivial o bastante para eu mostrá-lo aqui completamente. Assistam este vídeo que verão como fazer um prompt.

Quando usamos uma consulta MQL, de metadados, aplicar a restrinção é um pouco mais simples. Os passos são esses:

  1. Construa um relatório com MQL, como o que fizemos no post passado;
  2. Crie uma consulta (MQL, SQL, tanto faz) que retorne a lista de opções que o cliente pode selecionar;
  3. Crie o parâmetro no PRD usando essa consulta como fonte;
  4. Volte para a consulta principal e, usando a interface de criação de consultas, adicione o filtro e insira o parâmetro.

No nosso caso vamos filtrar o relatório de vendas do Alexandre por UF.

Primeiro, construímos uma consulta em MQL que traz a lista de estados:

Lista de UFs criada no construtor de consultas MQL.
Lista de UFs criada no construtor de consultas MQL.

O MQL dessa consulta é:

    <mql>
      <domain_type>relational</domain_type>
      <domain_id>BeltranoOLTP</domain_id>
      <model_id>BV_MODEL_1</model_id>
      <model_name>Beltrano OLTP</model_name>
      <options>
        <disable_distinct>false</disable_distinct>
        <limit>-1</limit>
      </options>
      <selections>
        <selection>
          <view>BC_CLIENTES_PF</view>
          <column>BC_ESTADOS_UF_2</column>
          <aggregation>none</aggregation>
        </selection>
      </selections>
      <constraints/>
      <orders>
        <order>
          <direction>asc</direction>
          <view_id>BC_CLIENTES_PF</view_id>
          <column_id>BC_ESTADOS_UF_2</column_id>
        </order>
      </orders>
    </mql>
    </pre>

Construímos um paramater alimentado por essa consulta, chamado UF:

Novo parâmetro UF, alimentado pela consulta Query 2 do metamodelo.
Novo parâmetro UF, alimentado pela consulta Query 2 do metamodelo.

Depois inserimos esse parâmetro, UF, na consulta que popula o relatório: colocamos a coluna que vai ser filtrada na seção constraints e aplicamos uma igualdade para o parâmetro.

Inserindo o parâmetro na consulta principal com o editor de MQL.
Inserindo o parâmetro na consulta principal com o editor de MQL.

O truque é envolver o parâmetro em chaves, { e }. Com isso o construtor de consultas reconhece que se trata de um parâmetro e não de um valor ordinário, e ajusta a consulta automaticamente. A título de comparação, observe o filtro para pegar apenas as vendas do Alexandre.


Ao adicionar um nome cercado por { e } nos filtros, o construtor de consulta realiza duas coisas:

  1. Define um parâmetro no início da consulta
    <mql>
      <domain_type>relational</domain_type>
      <domain_id>BeltranoOLTP</domain_id>
      <model_id>BV_MODEL_1</model_id>
      <model_name>Beltrano OLTP</model_name>
      <options>
        <disable_distinct>false</disable_distinct>
        <limit>-1</limit>
      </options>
      <parameters>
        <parameter defaultValue="XX" name="UF" type="STRING"/>
      </parameters>
      <selections>
        <selection>
          <view>BC_PEDIDOS</view>
    <...restante da consulta...>        
    
  2. E usa esse parâmetro na seção conditions:
    <...começo da consulta...>
      <constraints>
        <constraint>
          <operator>AND</operator>
          <condition>CONTAINS([BC_PEDIDOS.BC_VENDEDOR_NOME_COMPLETO];"Alexandre")</condition>
        </constraint>
        <constraint>
          <operator>OR</operator>
          <condition>[BC_CLIENTES_PJ.BC_ESTADOS_UF_3] = [param:UF]</condition>
        </constraint>
      </constraints>
    

Ao rodar o relatório o PRD cria e apresenta um controle do tipo drop-down, populado com a lista dos estados. Sempre que um estado é selecionado, o relatório é automaticamente filtrado:

Filtro aplicado em consulta MQL.
Filtro aplicado em consulta MQL.

Um bom uso dessas possibilidades é criar relatórios que se adequam a cada usuário: basta usar o parâmetro pré-definido env::username para filtrar a consulta pelo nome do usuário na plataforma desde que esse usuário possua um nome igual registrado no banco de dados.

Por exemplo, se eu registrar no Pentaho BA Server os vendedores com o mesmo nome que possuem no Beltrano OLTP, eu posso filtrar os dados montando uma constraint do tipo Vendedor CONTAINS {env::username}.

Experimente!

8.3 Segurança

Por fim, mas não menos importante, um metamodelo pode restringir o conteúdo de uma consulta em função das permissões de acesso – controle de segurança – dos dados.

Como sempre, a idéia é simples: definimos um filtro de dados no metamodelo que usa o nome do usuário e, eventualmente, seu papel, para montar um controle de exibição baseado no controle de acesso.

Como fazer:

  1. No Pentaho BA Server, usando o papel de administrador, registre todos seus usuários. Eu fiz isso com os usuários da Beltrano;
  2. Com Pentaho Metadata Editor edite o metamodelo e registre um filtro no nível do modelo de negócio, seção Data Constraints: qualquer consulta contra esse modelo de negócio vai embutir aquele filtro automaticamente. Salve e publique o metamodelo no servidor;

    Registrando filtro no PME.
    Registrando filtro no PME.
  3. No PRD basta remover qualquer filtro local. Por exemplo, eu removi o filtro de usuário “Alexandre”, deixando o relatório trazer dados de todos os vendedores, indistintamente. Salvei e publiquei o metamodelo.

Feito! :-)

Para testar, acessei a plataforma com duas contas: Fábio e Alexandre. Como o relatório consome metadados, e os metadados são completamente filtrados por meio do atributo Data Constraints no Business Model, os dados apresentados já estão filtrados.

Resultado do filtro por controle de segurança.
Resultado do filtro por controle de segurança.

8.4 Conclusão

“Nossa, Fábio! Que maravilha!”, dirão vocês, “e não tem nenhuma desvantagem?”

Sim, tem: justamente adicionar uma outra camada para manutenção. Se usamos apenas SQL, qualquer alteração no banco entra em efeito imediatamente para o relatório. Se usarmos um metamodelo vamos precisar atualizar a camada de metadados antes de poder sequer testar as mudanças no PRD. Fazer uma pequena alteração na formatação pode forçar o analista a quebrar o vínculo do campo com a metaconsulta, perdendo a vantagem do modelo centralizado, ou então obrigar a uma atualização do metamodelo, cascateando a publicação de uma nova versão.

Há uma segunda desvantagem, mas é mais sutil e, talvez, pior: aparentemente não há como fazer UNIONs! Isso não é um problema para modelos bem comportados, mas modelos como o do Beltrano – que nem é tão exótico assim – se quebram quando tentamos fazer certas combinações numa só consulta. Por exemplo, no modelo transacional, não é possível escrever um único SQL que traga todos os clientes PF e PJ. É preciso duas consultas, coladas a posteriori com UNION, para então chegar ao conjunto completo. E eu não achei como fazer isso com MQL.

Ou seja, as vantagens de uso de um metamodelo vêm com um preço: um processo de desenvolvimento com mais alguns passos. Se isso vai compensar no final é uma questão respondida projeto a projeto.

Até a próxima! :-)