PDI 8.x/9.x no Ubuntu 20.04

Pessoal, alguém está com problemas para rodar o PDI 8.x ou 9.x no ubuntu 20.04?

Esse erro acontece de repente, sem motivo aparente. Ele está ligado a uma biblioteca do sistema operacional que foi removida na versão 20.04 (abril de 2020) do Ubuntu e, apesar de chato, não é um erro grave – podemos continuar usando o Spoon normalmente.

Mas não precisa ser assim. O grupo de WhatsApp de Palestrantes Pentaho bateu uma bola ontem e o Emannuel Roque veio com uma solução, que ele encontrou no forum do Pulse, que teve o mesmo problema. Eu testei e funcionou.

Primeiro, garanta que esteja com o Java da Sun, ops, Oracle. Apesar de a página de referência dizer que o OpenJDK serve, eu prefiro o da Oracle. Para qualquer um dos dois use a versão 8, ou você terá problemas:

Depois, usando a linha de comando, adicione o repositório do Ubuntu 18.04:

sudo add-apt-repository 'deb http://archive.ubuntu.com/ubuntu bionic main universe'

Esse comando deve atualizar o cache local automaticamente. Se não atualizar, comande:

sudo apt update

Quando acabar de atualizar, instale a biblioteca faltante:

sudo apt install -t bionic libwebkitgtk-1.0-0

Pronto! É só rodar o Spoon 8.x ou 9.x e correr pra galera! :-)

(Não me perguntem, isso veio com a dica do Emannuel! Kkkkkk….)

Analisando os Logs do PDI – Parte 2

No primeiro post da série Logs do PDI vimos como configurar as transformações e jobs do PDI para capturar os logs de processamento e como usá-los para monitorar as execuções. Neste segundo post veremos como usar esses dados para identificar gargalos.

Pias & Transformações

Imagine uma pia, na qual uma torneira despeja água. Se entrar mais água do que a pia consegue escoar, a água vai começar a se acumular. Se nada for feito, o nível de água na pia vai subir, e subir, até transbordar. Há duas formas de se evitar que a água transborde: reduzir a entrada ou aumentar a saída. Em termos mais genéricos, para evitar que a água transborde devemos condicionar a entrada à restrição. A “restrição” é justamente a válvula de escoamento da pia.

A velocidade de uma transformação, medida em linhas por segundo, l/s, está condicionada à restrição existente na transformação: a velocidade de uma transformação será igual à velocidade do seu passo mais lento. Esse passo mais lento é o gargalo.


Se uma transformação possuir passos de ordenação de linhas, agrupamentos etc., que represam linhas, a velocidade média da transformação perde essa relação direta. Ainda vai haver uma relação entre a velocidade da transformação e a velocidade do seu passo mais lento, apenas não será mais 1 para 1. Mas, para manter o didatismo do post, vamos assumir uma transformação perfeitamente esférica e sem atrito, na qual essa condição vale. ;-)


Para aumentar a velocidade de uma transformação, portanto, devemos aumentar a velocidade do fluxo (em l/s) no gargalo. Quando a velocidade no gargalo tiver subido o bastante, algum outro passo vai ser o responsável por restringir a velocidade da transformação, se transformando no novo gargalo. Removemos esse novo gargalo, aumentando a velocidade da transformação, e outro aparecerá, reiniciando o processo. Eventualmente, chegaremos num ponto de rendimento máximo da transformação, no qual uma nova mudança em qualquer passo não vai resultar em aumento de velocidade da transformação.

Simples, não?

Engarrafamento de Linhas

E como descobrimos gargalos em uma transformação?

Usando o Spoon para detectar gargalos: notou um pontilhado em volta de algum passo? É um gargalo!
Usando o Spoon para detectar gargalos: notou um pontilhado em volta de algum passo? É um gargalo!

Se você estiver rodando-a no Spoon, a interface gráfica do PDI, é muito fácil. O PDI detecta o gargalo, definido por ele como “o passo que recebe mais linhas do que é capaz de processar”, e faz com que o Spoon apresente um pontilhado animado em volta de cada passo identificado como gargalo. Esse monitoramento ocorre em tempo real, e causa efeitos curiosos: em certas situações o gargalo parece “pular” entre dois ou mais passos, e em outras vários passos são marcados como gargalos, simultaneamente. A dinâmica que causa isso está fora do escopo deste post, mas não é difícil de entender se você parar para pensar um pouco.

Para que seu Spoon mostre esse passo na sua transformação você precisa habilitar o checkbox Show bottleneck transformation steps, conforme visto na figura abaixo. Essa janela aparece quando selecionamos o item Options, no menu Tools.

Onde fica o checkbox que habilita a exibição do gargalo.
Onde fica o checkbox que habilita a exibição do gargalo.

Essa opção é muito boa durante o processo de desenvolvimento, mas o que fazer para transformações que rodamos em produção? É um ambiente diferente – memória diferente, disco diferente, carga (tarefas simultâneas) diferentes! Se bobear até o sistema operacional é diferente! Não dá para rodar uma por uma no Spoon e ficar olhando, esperando encontrar um passo-gargalo.

Você adivinhou: consultamos o log de performance.

Entendendo o Gargalo

Conforme o próprio PDI coloca, um gargalo (ou restrição) é “um passo que recebe mais linhas do que é capaz de processar”. Para entender isso você precisa saber um pouco sobre a estrutura interna de um passo.

Um passo possui, grosso modo, três partes:

  1. Buffer de entrada: onde são gravadas as linhas que chegam do passo anterior, e onde elas ficam esperando ser processadas;
  2. Motor do passo: retira uma linha do buffer de entrada, processa e grava o resultado no buffer de saída, repetindo esse processo enquanto o passo anterior estiver mandando linhas;
  3. Buffer de entrada: onde são gravadas as linhas processadas pelo passo, e onde elas aguardam até o engine do PDI movê-las para o passo seguinte.
Todo passo possui dois buffers: entrada e saída.
Todo passo possui dois buffers: entrada e saída.

Assim, se o motor do passo, o processamento em si, não for rápido o bastante, ele começa a ficar para trás: as linhas começam a se acumular no buffer de entrada. Se, além disso, se o passo seguinte for no mínimo tão rápido quanto o passo atual, as linhas processadas não “esquentam cadeira” no buffer de saída, e vão sendo levadas adiante. Por exemplo, na transformação simples mostrada abaixo, com três passos, o passo do meio é um gargalo:

O passo do meio é um gargalo: buffer de saída com menos linhas que o de entrada.
O passo do meio é um gargalo: buffer de saída com menos linhas que o de entrada.

Note que os buffers do passo do meio, representados pelas caixas de entrada e saída, aparecem vazio na saída e cheio na entrada. Essa é a condição de gargalo, ou de restrição. Se pudermos aumentar (elevar) a vazão dessa restrição, a velocidade da transformação, como um todo, aumentará.

Como vemos isso nos logs? Bom, quando rodamos uma transformação no Spoon, este monta um quadro de métricas dos passos, e atualiza-o conforme a transformação vai sendo executada, conforme as linhas vão sendo processadas.

Passos e seus parâmetros durante execução.
Passos e seus parâmetros durante execução.

A coluna input/output, última à direita na imagem anterior, exibe a relação entre a quantidade de linhas presentes no buffer de entrada, aguardando processamento, e quantidade de linhas no buffer de saída, aguardando transporte até o passo seguinte. Sempre que um passo possui mais linhas em sua entradas que em sua saída, ele está “segurando” a transformação. Para encontrarmos os gargalos de uma transformação, então, basta analisarmos os passos dela, em busca de buffers de entrada cheios e buffers de saída vazios (ou com bem menos linhas.)

Analisando Vazão em Transformações

O log que captura as métricas de cada passo, segundo a segundo, chama-se Performance. Veja como ativá-lo no primeiro post da série. Essa tabela possui as seguintes colunas:

  • id_batch
  • seq_nr
  • logdate
  • transname
  • stepname
  • step_copy
  • lines_read
  • lines_written
  • lines_updated
  • lines_input
  • lines_output
  • lines_rejected
  • errors
  • input_buffer_rows
  • output_buffer_rows

Reparou nas duas últimas? São as que nos interessam.


Não vou montar uma solução pronta, mas mostrar como usar essa tabela para desenhar algo que atenda à sua necessidade – e depois vou mostrar um exemplo do relatório que eu uso para “debugar” transformações em produção.


Precisamos de uma consulta que traga os buffers, por cada passo, por transformação. Além disso, como cada transformação pode ter sido executada várias vezes, precisamos filtrar também por lote (id_batch.) Essa consulta ficaria assim:

SELECT
  id_batch,
  transname,
  stepname,
  input_buffer_rows,
  output_buffer_rows
FROM transformation_performance
WHERE
  id_batch = X AND
  transname = 'x'

Filtrando para lote 2080 e transformação Carga da Lista de Clientes PF, temos:

id_batch transname stepname input_buffer_rows output_buffer_rows
2080 Carga da Lista de Clientes PF Gera strings aleatórias 224 276
2080 Carga da Lista de Clientes PF Cria CEP, Telefone e Fax 0 0
2080 Carga da Lista de Clientes PF Cria CEP, Telefone e Fax 0 0
2080 Carga da Lista de Clientes PF Lê nomes 0 0
2080 Carga da Lista de Clientes PF Cria as partes de CEP, Telefone e Fax 0 0
2080 Carga da Lista de Clientes PF Muda rnd_telefone/fax para string 0 0
2080 Carga da Lista de Clientes PF Seleciona endereço 2 0
2080 Carga da Lista de Clientes PF Lê sobrenomes 0 61
2080 Carga da Lista de Clientes PF Acerta tamanho das strings 0 0
2080 Carga da Lista de Clientes PF Seleciona sobrenome 61 0
2080 Carga da Lista de Clientes PF Lê lista de enderecos 0 0
2080 Carga da Lista de Clientes PF Seleciona nome 0 0
2080 Carga da Lista de Clientes PF Cria ID do Cliente 1560 225
2080 Carga da Lista de Clientes PF Insere cidade_id 1 3
2080 Carga da Lista de Clientes PF Limpa fluxo 0 0
2080 Carga da Lista de Clientes PF Cria índice do endereço 276 125
2080 Carga da Lista de Clientes PF Gerar linhas 0 2444
2080 Carga da Lista de Clientes PF Cria índices de nome 147 110
2080 Carga da Lista de Clientes PF String operations 3 1
2080 Carga da Lista de Clientes PF Absoluto de rnd_cpf 110 3
2080 Carga da Lista de Clientes PF Grava tabela 0 0
2080 Carga da Lista de Clientes PF Gera strings aleatórias 1778 5755
2080 Carga da Lista de Clientes PF Cria CEP, Telefone e Fax 0 0

E aí, consegue dizer se algum destes passos é um gargalo? Nem eu. Vamos melhorar nossa consulta: vamos agrupar por passo, remover o nome da transformação e lote da execução, já que ambos são previamente conhecidos (estão no filtro.) Fica assim:

SELECT
  stepname,
  sum(input_buffer_rows) as buffer_entrada,
  sum(output_buffer_rows) as buffer_saida
FROM transformation_performance
WHERE
  id_batch = 2080 AND
  transname = 'Carga da Lista de Clientes PF'
GROUP BY
  stepname
ORDER BY
  stepname

Resultado:

stepname buffer_entrada buffer_saida
Absoluto de rnd_cpf 4289 2770
Acerta tamanho das strings 10117 10100
Cria as partes de CEP, Telefone e Fax 100 10098
Cria CEP, Telefone e Fax 10101 20099
Cria ID do Cliente 21021 11892
Cria índice do endereço 15660 3458
Cria índices de nome 3483 4289
Gerar linhas 0 21902
Gera strings aleatórias 11889 15658
Grava tabela 20281 0
Insere cidade_id 202 259
Lê lista de enderecos 0 0
Lê nomes 0 0
Lê sobrenomes 0 61
Limpa fluxo 20099 20281
Muda rnd_telefone/fax para string 125 100
Seleciona endereço 258 714
Seleciona nome 714 100
Seleciona sobrenome 161 125
String operations 2770 202

Já dá para dizer se alguém é gargalo? Não! Veja, buffer de entrada e buffer de saída são métricas não-aditivas: somá-las ao longo do tempo não dá nenhuma informação sobre o processo. Nem somando-as ao longo dos passos, ou das transformações, nada! No máximo, como métricas não-aditivas, talvez uma média ao longo do tempo possa dar alguma idéia do que está acontecendo.

Mesmo assim, a média não ajudaria. Lembra-se que o monitoramento de gargalo do Spoon ocorre em tempo real? E que os gargalos podem pular de um passo para outro? Só conseguimos identificar um gargalo olhando o comportamento dele ao longo do tempo, momento a momento.

Incluíndo o tempo na consulta, temos:

SELECT
  stepname,
  logdate,
  sum(input_buffer_rows) as buffer_entrada,
  sum(output_buffer_rows) as buffer_saida
FROM transformation_performance
WHERE
  id_batch = 2080 AND
  transname = 'Carga da Lista de Clientes PF'
GROUP BY
  stepname,
  logdate
ORDER BY
  stepname

Vai nos dar a seguinte saída:

stepname logdate buffer_entrada buffer_saida
Absoluto de rnd_cpf 2016-02-21 16:34:41 110 3
Absoluto de rnd_cpf 2016-02-21 16:34:41 110 3
Absoluto de rnd_cpf 2016-02-21 16:34:42 87 100
Absoluto de rnd_cpf 2016-02-21 16:34:43 4092 2667
Absoluto de rnd_cpf 2016-02-21 16:34:44 0 0
Absoluto de rnd_cpf 2016-02-21 16:34:45 0 0
Absoluto de rnd_cpf 2016-02-21 16:34:46 0 0
Absoluto de rnd_cpf 2016-02-21 16:34:46 0 0
Acerta tamanho das strings 2016-02-21 16:34:41 0 0
Acerta tamanho das strings 2016-02-21 16:34:42 0 0
Acerta tamanho das strings 2016-02-21 16:34:43 120 100
Acerta tamanho das strings 2016-02-21 16:34:44 9997 10000
Acerta tamanho das strings 2016-02-21 16:34:45 0 0
Acerta tamanho das strings 2016-02-21 16:34:46 0 0
Acerta tamanho das strings 2016-02-21 16:34:46 0 0
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:41 0 0
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:42 0 0
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:43 100 101
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:44 0 9997
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:45 0 0
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:46 0 0
Cria as partes de CEP, Telefone e Fax 2016-02-21 16:34:46 0 0
Cria CEP, Telefone e Fax 2016-02-21 16:34:41 0 0
Cria CEP, Telefone e Fax 2016-02-21 16:34:42 0 0
Cria CEP, Telefone e Fax 2016-02-21 16:34:43 101 100
Cria CEP, Telefone e Fax 2016-02-21 16:34:44 10000 10000
Cria CEP, Telefone e Fax 2016-02-21 16:34:45 0 9999
Cria CEP, Telefone e Fax 2016-02-21 16:34:46 0 0

Agora podemos dizer, se em algum instante, um passo se comportou como um gargalo. Claro que examinar os dados assim é uma bobagem – podemos montar um gráfico com isso.

Relatório de Análise de Fluxos

Juntando essa consulta com os relatórios do primeiro post, montamos um relatório de análise de fluxo de transformações:

Relatório de análise de fluxo em transformações.
Relatório de análise de fluxo em transformações.

Esse relatório traça a velocidade daquele passo em linhas por segundo no gráfico de cima, e o volume de linhas presentes nos buffers, no gráfico de baixo, tudo instante a instante. O que vemos é que esse passo possui uma vazão boa, até, de 20.000 l/s, e que ele nunca esteve em condição de gargalo. Muito pelo contrário: no instante 5 ele teve o seu buffer de saída completamente cheio, sugerindo que o passo seguinte poderia ser um gargalo.

Eis o trecho da transformação que estamos analisando:

Trecho final da transformação de carga de clientes PF da Beltrano S/A.
Trecho final da transformação de carga de clientes PF da Beltrano S/A.

Os passos seguintes são um Select Values e um Table Output. Eis os buffers do Select Values:

Buffers do Select Values.
Buffers do Select Values.

E os do Table Output:

Buffers do Table Output.
Buffers do Table Output.

A-há! Veja ali, do momento 3 ao momento 6, como o buffer de entrada (a linha vermelha) sobe até atingir 10.000 linhas, enquanto o buffer de saída permanece em zero! Esse passo é um gargalo! Ele ficou com o buffer de entrada cheio, que fez com que as linhas “transbordassem” para o passo anterior, o Select Values. Tanto esse Select Values não é um gargalo que os dois buffers sobem e descem juntos. Mais ainda: foi justamente entre os momentos 3 e 6 (comuns a todos os passos, aliás, pois o log de performance captura todo mundo junto) que o buffer de saída do passo Cria CEP, Telefone e Fax saturou, isto é, atingiu seu limite de 10.000 linhas, e começou a se refletir no buffer de entrada, mesmo que por apenas um segundo (cada momento equivale a um segundo nesta escala.)

Conclusão

A partir da consulta mostrada podemos criar um relatório que exibe o estado dos buffers de cada passo momento a momento. Usando a transformação como guia, podemos analisar cada um dos passos em busca do sintoma de restrição de fluxo.

Essa não é a melhor análise, já que nos obriga a olhar um por um. Como você faria essa análise automaticamente? Como deixar para o Report Designer detectar os gargalos de uma transformação?

E apenas para fechar o problema encontrado neste exemplo: um gargalo em um passo que grava dados no banco significa que a rede e o banco é que são os gargalos. Dependendo da influência da rede e do banco na força da restrição, podemos levar o processamento para mais perto (reduzindo o custo da rede) ou melhorar o banco com, por exemplo, discos mais rápidos.

Na próxima semana terminaremos a série com um relatório de genealogia de um processo de ETL.

Até lá!


Novo Lançamento!

Sexta-feira, 11 de março de 2016, será o lançamento do meu novo livro, Autopublicação na Prática. Não deixe de passar por aqui, porque – como sempre – ele será lançado por R$ 0,00!

Como Criar uma Dimensão Data

Em um Modelo Dimensional, o recurso mais valioso sem sombra de dúvida é uma boa dimensão Data. Ainda que uma estrela (um conjunto fato-dimensões) seja em si mesma um grande recurso analítico, ela é pouco útil se não agregar a capacidade de analisar os dados contra o tempo.

Kimball comenta o seguinte sobre a dimensão Data:

Kimball comenta sobre a dimensão Data.
Kimball comenta sobre a dimensão Data.

A sugestão é simples e muito prática: baixe este arquivo do site dele, copie a coluna com os INSERTs e cole num terminal SQL. Repare que, no comentário acima, ele ainda menciona a necessidade de se criar uma linha extra, com chave especial (zero?) para os fatos que ainda não tem data.

Usando o Pentaho Data Integration

No meu livro Pentaho na Prática há uma outra forma de se popular uma dimensão data, que é usando esta transformação do PDI:

Transformação para popular uma dimensão Data.
Transformação para popular uma dimensão Data.

Ela gera 10.000 linhas, a partir de 1/jan/1990, com dia da semana e mês, em inglês. Se você quiser traduzir, basta editar o conteúdo dos passos Days of week e Months. Porém, da mesma forma que a planilha do Kimball, essa transformação não cuida do registro zero – você deve inseri-lo manualmente.

Clique aqui para baixar o arquivo. Depois de descompactá-lo e abri-lo com o PDI, você precisa configurar apenas o último passo (figura abaixo: selecione uma conexão, informe o esquema se for necessário, e depois inserir o nome da tabela) e clicar no botão SQL para automagicamente criar a tabela.

Passo de saída para a transformação que popula a dimensão data.
Passo de saída para a transformação que popula a dimensão data.

Essa transformação vem na pasta de amostras do PDI 3.8. Infelizmente, as versões posteriores passaram a vir corrompidas.

Gravar Fato com Dimension Lookup/Update

Inteligência e criatividade já foram definidas como misturar coisas com um propósito e atingir outro. Eu tive o melhor exemplo disso há pouco, durante uma aula.

Explicando a gravação de uma fato, e peculiariedades de cada tipo de fato (snapshot, acumulating etc.), ela me perguntou:

Ah, então eu posso gravar a fato com a Table Output, e se quiser atualizar uso um Dimension Lookup/Update?”

De cara eu não entendi a pergunta – “Comparar table output com dimension lookup/update? Mas não tem nada a ver…” – foi quando eu parei para pensar e vi que era não só uma pergunta lógica, como óbvia.

Sim, claro, o D L/U (Dimensio Lookup/Update) é um passo dedicado a gravar dimensões, mas a lógica dele se presta a qualquer gravação/atualização que envolva uma chave composta e “coisas” (métricas!) que variem (ou não.)

Eu resolvi fazer um teste. Essa é a transformação que grava a fato pedido da Beltrano S/A, tirada do meu livro Pentaho na Prática:

Transformação que carrega a fato, usando passo "normal" Insert/Update.
Transformação que carrega a fato, usando passo “normal” Insert/Update.

Eu então troquei o Update no final por um D L/U – e não mexi em mais nada:

Transformação que carrega a fato, usando passo D L/U.
Transformação que carrega a fato, usando passo D L/U.

E essa ficou sendo a configuração do passo (eu tratei o tipo de pagamento como uma degeneração, mas sem querer coloquei como métrica):

Configuração do passo D L/U para gravar uma fato.
Configuração do passo D L/U para gravar uma fato.

Resultado? Bom, depois que eu criei a fato com o botão de SQL do D L/U e carreguei, ela ficou assim:

Fato gravada pelo passo D L/U. Repare que todos campos de controle da dimensão foram chamados de fut_ext_x (futuras extensões), e que agora ela possui uma chave primária.
Fato gravada pelo passo D L/U. Repare que todos campos de controle da dimensão foram chamados de fut_exp_x (futuras extensões), e que agora ela possui uma chave primária.

Ou seja, é a fato, mas com os campos de controle da dimensão. Eu nomeie todos eles como futuras expansões (fut_exp). A chave delegada também está lá, mas agora na função de uma chave primária! Compare com a fato “normal”:

A tabela fato gravada com um passo normal. (As chaves zeradas são um bug da minha transformação, que está bagunçada (sabe como é, próxima versão do livro...)
A tabela fato gravada com um passo normal. (As chaves zeradas são um bug da minha transformação, que está bagunçada (sabe como é, próxima versão do livro…)

Os zeros nas chaves decorrem do fato de a minha transformação estar em mudança – por algum motivo eu não recuperei as chaves (pau do banco?) – mas normalmente dá certo. Por favor, releve como ruído no material do livro, que está sendo revisado.

Conclusão? Dá certo! (Claro que dá, mas… como é que eu nunca pensei nisso antes???) Será que é alguma vantagem usar o D L/U para isso? Será que simplifica alguma lógica? A ver!

Genial! :-)

Novo Livro: Pentaho Data Integration Cookbook – Segunda Edição

Um cookbook é um livro de receitas (recipes), e normalmente se vale de o leitor possuir algum conhecimento sobre o assunto (culinária via de regta) para ensinar algumas receitas. Por exemplo, para aprender a fazer um bolo você precisa saber quebrar ovos, que é algo que ninguém te ensina – um dia você viu alguém quebrar ovos para cozinhar e pronto, hora da receita (Recipe Time!)

Eu ganhei da Packet mais um livro sobre Pentaho para resenhar, o Pentaho Data Integration Cookbook (Segunda Edição), lançado há algumas semanas. Ele não ensina como instalar o PDI, ou rodá-lo, nem explica o que é uma transformação, um job e como criar um novo de cada. Isso é tarefa para outros livros, como o também excelente Pentaho 3.2 Data Integration: Beginner’s Guide.

O PDI Cookbook te ensina receitas, pequenos how-to, para mais de 100 objetivos. Ele tem receitas para ensinar a conectar uma transformação a um banco de dados, e como parametrizá-la (e porquê), uma para ler dados de tabelas em bancos relacionais, outra para construir e usar sub-transformações e ainda outras sobre como gravar os dados em clusters Hadoop, manusear o fluxo e os metadados de transformações, executar análises de dados, gerar relatórios, executar dentro do BI Server e assim por diante. Ele não esgota as possibilidades, mas chega bem perto de. Você pode consultar a página do livro na Packt, aba Table of Contents, para ver a lista completa.

Estou com o livro há duas semanas e ainda não li o livro todo, mas olhei uma boa parte delas e fiz questão de ler com cuidado algumas receitas sobre coisas que eu conheço (como conexões parametrizadas, leitura de dados, lookups e fluxos) e algumas sobre coisas que eu nem imagino como sejam (como ler e gravar dados do Salesforce.com e do Hadoop.)

Cada receita demanda algum conhecimento prévio do leitor, mas tem informação o bastante para não deixar dúvidas para os iniciantes, sem aborrecer o leitor mais experiente. As figuras são usadas com parcimônia, notadamente quando os autores sentem necessidade delas para explicar melhor algum detalhe ou comunicar uma configuração com mais precisão. Se por um lado isso torna o livro menor (e ele já um bom catatau, com mais de 400 páginas), por outro força o leitor a prestar mais atenção e requer mais familiariedade com os termos envolvidos. Ele não dá tudo mastigadinho, mas tem boa didática e os textos são bem escritos (mais sobre isso daqui a um parágrafo.)

Muitas (se não todas) receitas trazem dicas sobre eventuais opções ou formas alternativas de se obter o mesmo resultado, ou ainda alguma variação sobre o tema. Em várias das receitas que eu li há comparações entre métodos (como o lookoup de dados, que explicita a diferença entre Database Lookup e Database Join, por exemplo) e em geral há comentários sobre impactos de performance quando são significativos. A location 400 traz um dos meus favoritos, pela engenhosidade: usar bancos de dados em memória (como HSQDB ou H2) para montar lookups transitórios de alta performance.

Claro que, como a maioria dos livros da Packt é escrita em inglês por não-nativos, a linguagem do livro é por vezes menos fluída que o inglês de um norte-americano ou britânico (ou mesmo um aussie.) Acho que essa é única coisa do livro que é mais… desconfortável, mas decididamente não afeta o resultado final.

Enfim, o livro é um verdadeiro baú do tesouro, com grande valor para desenvolvedores novatos ou experientes. Se você já sabe mexer com o PDI, e quer se aprofundar nele, esse livro é uma boa escolha. Se você quer aprender a mexer no PDI, procure antes algo como o PDI Begginer’s Guide, e depois não deixe de investir no PDI Cookbook (mas a segunda edição; a primeira ainda tinha espaço para melhorar, tanto que foi o que fizeram.)

É isso, grande leitura! ;-)

Exportando Dados com BI Server

O Pentaho é uma plataforma de construção de soluções de BI. Ele atende muitas necessidades, cada qual de uma maneira. Para quem está acostumado com o MicroStrategy, por exemplo, pode ficar um pouco chocado – como, não é só fazer um relatório? Pois é, o Pentaho faz bem mais coisas que “relatórios” e hoje eu vou mostrar aqui um truque eu aprendi com o (blog do) Nicholas Goodman, neste post. O site do blog dele, aparentemente, sumiu e esse é um dos motivos que me levou a postar aqui a mesma coisa. Repare que esse mesmo post também existe no fórum da Pentaho, neste link, ainda que sem as imagens ou arquivos.

O Problema

… é simples: seu usuário precisa “extrair os dados” da sua base (um DW, possivelmente) para usá-los em alguma outra atividade. Bom, seu cliente deveria gastar mais tempo com você e desenharem juntos uma solução com o Pentaho. Mas já que ele prefere ter mesmo tudo nas próprias mãos, vamos dar a ele a solução Pentaho que faz exatamente isso: baixa um pacotão com os dados extraídos do(s) banco(s).

A Solução

… é simples, também: vamos criar uma XAction no BI Server que, ao ser executada, baixa um arquivo de dados formatos em CSV. O “projeto” da solução é o seguinte:

  1. Usando o Spoon construa uma transformação que recupera os dados desejados. Por isso eu escrevi fontes de dados, no plural: com o PDI você pode combinar quantas quiser e ainda montar alguma coisa em cima;
  2. Crie a área de depósito, ou landing zone, na qual vamos deixar o arquivo que o usuário vai recuperar.
  3. Vá até o BI Server e crie uma nova solução (pasta de nível zero);
  4. Coloque a transformação dentro desta pasta;
  5. Construa a XAction que executa a transformação e devolve o arquivo.

A Implementação

Vamos passo-a-passo, mas eu preciso partir de um mínimo. Eu vou assumir que você:

  • Já sabe usar o PDI (a.k.a. Kettle) para construir transformações;
  • Consegue configurar e usar um BI Server, incluindo adicionar drivers;
  • Sabe usar o Pentaho Design Studio para construir e implantar XActions.

Se você ainda não sabe alguma dessas coisas deixe um comentário que darei algumas dicas, ou me procure no Linkedin (Fábio de Salles).

Primeira Passo: Construindo a Consulta

Digamos que meu cliente, que é o Analista de Data Mining da Beltrano S/A (a empresa que usamos no livro) e quer uma listagem com todos os atributos dos pedidos, extraídos diretamente da base transacional (beltrano_oltp). Ele me deu o SQL, que é:

SELECT
pedidos.data_pedido,
pedidos.cliente_tipo,
pedidos.pagamento_tipo,
pedidos_detalhes.quantidade,
pedidos_detalhes.desconto,
pedidos_detalhes.total_item,
pedidos_detalhes.preco_unitario,
turmas.data_turma,
cursos.curso_nome,
cursos.duracao_total,
cursos.duracao_aula,
cursos.vagas,
cursos.preco_vaga,
pedidos.cliente_id,
pedidos.pedido_id
FROM
public.cursos,
public.pedidos,
public.turmas,
public.pedidos_detalhes
WHERE
pedidos.pedido_id = pedidos_detalhes.pedido_id AND
turmas.curso_id = cursos.curso_id AND
pedidos_detalhes.turma_id = turmas.turma_id;

De posse desse SQL eu crio uma transformação que executa-o e grava o resultado em um arquivo CSV, zipado para ocupar menos espaço e testo: (ops! minha base estava vazia quando eu fiz esse screenshot!)

Transformação pronta e funcionando!
Transformação pronta e funcionando!

Beleza, funcionou, etapa um pronta.

Segundo Passo: Preparando o BI Server

Em uma instalação padrão do BI Server (estou usando a 4.8), equipado com driver para meu banco (um Postgres), eu crio o diretório que vai receber o arquivo. Meu BI Server fica em /opt/pentaho/4.8/biserver-ce. Entro em tomcat, webapps e crio uma pasta chamada lz:

Pasta lz criada.
Pasta lz criada.

Agora eu subo o BI Server, faço login como joe e crio uma solução (=nome de pasta no nível zero):

Criada a solução na qual o cliente vai recuperar os dados.
Criada a solução na qual o cliente vai recuperar os dados.

Finalmente, eu volto à transformação e coloco como diretório do arquivo de saída a nova pasta lz, /opt/pentaho/4.8/biserver-ce/tomcat/webapps/lz:

Incluído diretório de saída da extração.
Incluído diretório de saída da extração.

Pronto, segunda etapa feita.

Terceira Etapa – XAction exporta_dados

Abra o Design Studio (estou usando o 4.0.0), aponte para o pentaho-solutions do BI Server 4.8 e crie uma nova XAction:

  1. Configure o PDS para apontar para ./biserver-ce/pentaho-solutions;
  2. Na pasta (solução) Exportacao de Dados crie uma nova XAction: clique com o botão da direita na pasta e selecione BI PlatformNew Action Sequence. Dê um nome (eu chamei de exporta_dados);
  3. Preencha a ficha de identificação com o que bem entender, apenas evite acentos e cedilhas;
  4. Mude para aba 2 (Define Process);
  5. Clique com o botão da direita sobre Inputs e selecione AddString;
    1. Nomeie a nova variável como redirect_uri;
    2. Ligue o check-box Has default value;
    3. Preencha o valor dela com o caminho do arquivo dentro da solução lz: /lz/dados.zip;
  6. Clique com o botão da direita sobre a área das Process Actions e selecione AddGet Data FromPentaho Data Integration;
    1. Clique sobre a nova Process Action e altere seu nome; eu mudei para Extrai para arquivo.
    2. Coloque o caminho da transformação em relação à solução (solution:/exporta_dados.ktr), no campo Transformation file;
    3. Ajuste apenas o Kettle logging level. Eu deixei em Minimal;
  7. Finalmente, adicione o comando que vai redirecionar o navegador para o arquivo que a transformação vai criar:
    1. Clique o sinal de + azul que existe na seção Process Outputs, e selecione a variável que criamos antes: redirect_uri;
    2. Clique sobre a variável, para selecioná-la, e clique no sinal de + azul, na folha de propriedades da variável de saída, e selecione response: redirect_uri;
    3. Dê um duplo-clique sobre redirect_uri e altere para redirect, apenas;
  8. Salve.
Adicionando saída que redireciona o navegador.
Adicionando saída que redireciona o navegador.

Para não ficar dúvidas:

Variável de saída redirect_uri.
Variável de saída redirect_uri.

E

Configuração da Action Sequence de transformação.
Configuração da Action Sequence de transformação.

Atualize o BI Server, para ele recarregar a XAction. Dê um duplo clique nela e veja a mágica acontecer: seu navegador vai dizer que tem um arquivo ZIP para baixar.

Dados, Trasnformação, Ação!
Dados, Trasnformação, Ação!

Voi là! Abra o arquivo e veja seu conteúdo: um CSV com os dados pedidos.

Conclusão

Por ser uma plataforma de BI e não uma ferramenta de visualização de dados OU de ETL OU de Data Mining OU … OU … etc., o Pentaho pode entregar muito mais que só relatórios. Certifique-se realizar uma entrevista detalhada e de explorar a necessidade e o uso que seu cliente vai dar ao projeto de BI, pois há muito mais ações entre o DW e os Dashboards que supõem nossos vãos relatórios.

Acidentalmente F2 Kettle Properties

De vez em quando um acidente nos dá um presente. Eu ia apertar “2” no teclado e meu embotado cérebro de fim-de-ano levou o dedo direto no “F2.” No milisegundo entre me tocar do erro e algo acontecer eu esperava que nada ocorresse, ou viesse uma mensagem de erro. Mas não, o que aconteceu foi o Spoon me mostrar essa tela:

Tela de entrada e edição de variáveis de ambiente no Spoon
Tela de entrada e edição de variáveis de ambiente no Spoon

É isso mesmo! Apertar F2 no Spoon (a interface gráfica do Pentaho Data Integration – ambos eternamente confundidos com o Kettle, antigo nome do PDI) mostra uma tela para editar as variáveis de ambiente do PDI! Basta clicar com o botão da direita do mouse sobre qualquer linha e selecionar “Insert before…” para criar uma nova variável. Assim que o Spoon é fechado, o arquivo de variáveis é regravado, e inclui quaisquer novas variáveis que você tenha criado.

Quaisquer novas variáveis usadas pelo PDI devem ser incluídas no kettle.properties. Quando estamos criando algo e descobrimos a necessidade por uma nova variável, devemos incluí-la no kettle.properties e recarregar o Spoon, para que ela seja carregada. Ou então devemos entrar a variável na tela de lançamento da transformação (que aparece quando você clica o botão de play ou aperta F9.) O primeiro te obriga a reabrir o Spoon quando precisar de uma nova variável. O segundo enche a paciência de cara, por te obrigar a (no mínimo) colar o mesmo parâmetro todas as vezes em que testar a tranformação.

Usando a tecla F2 Escapamos de editar o kettle.properties e restartar o Spoon, e da chateação que é inserir a variável o tempo todo na tela de execução da transformação!

E foi um acidente!

A Vantagem do Visual

Recebi o pedido de um post:

Fábio, você poderia fazer um post sobre sua experiência no pentaho referente a performance? Desenvolvo um projeto onde eu prefiro realizar todas as transformações via query e percebi que você utiliza os componentes do pentaho para fazer o mesmo. Como tenho poucos dados de testes quando vou testar a performance de ambos acaba dando quase o mesmo resultado em questão de tempo.

E é claro que eu vou atender. ;-)

Comparar ou Não Comparar, Eis a Questão

Suponha que eu escolha, como um exemplo para medir essa performance, copiar uma tabela para outra, no mesmo banco:

  • A query ganharia, já que nada bate uma cópia interna, de uma tabela para outra, dentro do mesmo banco.
  • Se a cópia fosse entre dois bancos diferentes, na mesma máquina, ainda seria muito rápido, mas acho que precisaria apelar para uma linguagem do banco, ou algum recurso não-padrão para que o SELECT em um banco sirva de entrada para o INTO em outro. Imagino que a consulta ainda bateria o PDI.
  • Agora, se a cópia fosse entre duas máquinas diferentes, talvez houvesse um empate porque a rede entre as máquinas passaria a ser um gargalo. Como os dois recursos (query e PDI) normalmente são muito mais rápido que a maioria das redes, a velocidade final seria limitada pela velocidade da rede, e daria empate.

Se eu escolhesse ler um arquivo e carregar no banco, os fatores envolvidos seriam outros e os resultados desse caso não teriam nenhuma relação com os resultados do caso anterior, da cópia entre duas tabelas. Se fosse um join, outro resultado. Se fosse um lookup em banco a partir de um arquivo, outro resultado. Etc. etc. etc. e assim por diante.

Ou seja, os resultados de uma comparação desse tipo seriam inconclusivos, pois oscilariam entre vantagem ora de um método, ora de outro.

Vendo Vantagem

Então tanto faz? A performance, na média, vai ser sempre a mesma para qualquer tecnologia?

Nem de longe. A comparação direta de performance entre as duas técnicas (PDI e SQL) pode ser uma medida muito difícil, mas não deve ser importante para optar por uma ou por outra. O que deve nortear sua escolha é, como sempre, o custo-benefício.

Se as suas transformações só envolvem bancos de dados, todos do mesmo tipo, pode ser que seja mais fácil desenvolvê-las usando SQL – já está tudo ali mesmo, e rodar SQLs diretamente no banco pode dar muito menos trabalho que baixar o PDI, configurar uma máquina, desenvolver as transformações e agendâ-las em produção.

Se o seu processo envolve arquivos (talvez em um servidor remoto), bancos (de diversos tipos), uma área de transferência temporária (palco ou stage) etc. etc. etc., desenvolvê-lo usando SQL pode ser tão complexo quanto construir uma nova aplicação do zero. Num caso desses, usar o PDI pode até redundar na mesma performance, mas o desenvolvimento desse processo será – eu te garanto – muito menos trabalhoso. Sua produtividade tende a ser mais alta com o PDI que com uma linguagem de programação.

Conclusão

A performance de cada processo depende de um sem-números de fatores, e o critério para você fazer uma escolha entre as tecnologias possíveis, em princípio, é o custo de cada uma dessas opções, comparado com o retorno que elas vão te dar.

Como o PDI permite desenhar todo processo graficamente, “ligando os passos”, um analista produz muito mais usando o PDI que desenvolvendo um programa em alguma linguagem.

Mas e a performance, Fábio? Afinal, qual eu devo escolher se a performance for importante? PDI ou Query?

PDI, sem sombra de dúvida. Porquê? Porque o PDI oferece muitos mecanismos para melhoria da performance do processo e você fatalmente vai conseguir a performance que precisa, a uma fração da complexidade do desenvolvimento de queries.

É isso.

Hackeando Transformações

Ocasionalmente precisamos alterar o volume de linhas lido de um banco por um Table Input, numa tranformação, para testar o processo inteiro. Se você tem apenas uma transformação, isso é fácil – basta abrir a transformação com o Spoon, alterar e testar.

E quando você acabou de montar o ETL inteiro, criou o job e ele vai levar algumas horas para rodar completamente? Cada teste de ponta-a-ponta pode levar algumas horas, e nós nunca queremos esperar horas para descobrir um erro numa RegEx no meio da última transformação. Não, especialmente quando não dá para rodar uma só de cada vez, mas precisamos rodar todas na sequência. E foi isso que me aconteceu: eu precisava testar a carga de certas variáveis e ver se todas as transformações de um ETL estavam tratando as variáveis corretas.

Eu poderia deixar o processo rodar e, a cada erro (que poderia ou não existir) eu corrigiria e reiniciaria tudo. Bummer! Horas para descobrir se havia erro, e mais horas para ter certeza que o consertara! Não, precisava haver uma forma melhor.

Como os arquivos eram todos texto (eu sempre salvo meus ETL em arquivo, raramente uso o repositório do PDI), eu tinha outra saída: um comando de linha que alterasse cada arquivo, mudando o limite de leitura de cada Table Input de 0 (infinitas linhas) para, por exemplo, 1000. Pedi ajuda a um grande e famoso (Wikipedia!!) amigo, Júlio Neves, que me deu o seguinte comando:

sed -i ‘s-<limit>0</limit>-<limit>1000</limit>-‘ *.ktr

Ele usa o Sed para alterar o parâmetro diretamente nos arquivos das transformações. Assim, com um comando de uma única e miseravelmente curta linha eu alterei o projeto todo!

Depois de finalizado o teste, o comando “reverso” leva o projeto de volta a seu estado original:

sed -i ‘s-<limit>1000</limit>-<limit>0</limit>-‘ *.ktr

Ou eu poderia simplesmente jogar as novas transformações fora e puxar do repositório de novo.

Observação: o Sed é um programa que faz parte da maioria (se não de todas) as distribuições Linux/Unix. Mas você pode tê-lo no Windows também. Basta instalar o Cygwin. É um pouco chato, para quem nunca mexeu com Linux, mas o poder que ela traz é proporcional. Vale a pena!