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!

Anúncios

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 Um Data Vault Evolui II

Em vários posts (Data Vault Para Quê?, Introdução à DV e Como um DV Evolui) eu falei sobre as vantagens em se ter um Data Vault no miolo do seu projeto de Data Warehouse Corporativo. (E eu também expliquei porque um DW é importante neste outro post.)

Hoje eu vou mostrar uma destas vantagens em ação: como um DV evolui quando a fonte de dados muda.

Cenário

Em julho de 2013 a equipe de desenvolvimento do DW Corporativo do SERPRO estava com um problemão: não conseguiam formular o modelo dimensional adequado à uma necessidade específica do cliente. Me convocaram a trabalhar no projeto e, depois de umas duas semanas apanhando “que nem” cachorro magro, eu consegui resolvê-lo. Ajustei o modelo, repassei os conceitos com a equipe, para evitar novos problemas do tipo, e saí do projeto no início de 2014.

Nessa época a arquitetura do projeto era a mais padrão possível, igual à de qualquer outra empresa:

Arquitetura original.
Arquitetura original.

Ou seja, os vários sistemas de origem eram lidos e partes de seus dados copiados para dentro de um outro banco de dados. Esse banco fazia algumas agregações, algumas integrações e produzia dados combinados. Esse banco não tinha o perfil de um palco (stage), apesar de concentrar dados, e por isso eu prefiro chamá-lo de ODS, ainda que também não se encaixe na perfeita acepção do termo. Finalmente, várias estrelas dimensionais eram populadas a partir da colagem que era esse ODS.

Eu construí a solução para a demanda do cliente em cima desta arquitetura, e percebi mais tarde que o que eu encontrara era, no fundo, a raiz de um modelo do tipo do Data Vault. Animado, eu redobrei meus estudos sobre DV, e no início de 2014 eu pude aplicar o que estava aprendendo para montar um DW na empresa de um amigo. Eu poderia ter feito tudo com Modelo Dimensional, mas seria uma boa chance de testar Data Vault. Deu muito certo: não apenas eu consegui desenvolver tudo em tempo recorde, como ainda criei um conjunto de templates, um processo de modelagem e um processo de desenvolvimento de ETL, que mais tarde foi usado no primeiro curso de Data Vault no Brasil.

Em novembro de 2014 eu voltei a ser alocado ao DW do SERPRO, para atender uma demanda, outra estrela, parada há alguns meses por falta de gente. Só que, desta vez,me deram a liberdade de aplicar meus conhecimentos de Data Vault e não perdi tempo:

Arquitetura com o Data Vault.
Arquitetura com o Data Vault.

Ou seja, meu novo ETL buscava no ODS os dados levados para o Data Vault, e deste um outro ETL partia com os dados para uma estrela de apresentação. Como meu DV foi preparado para se ajustar ao Data Mart Dimensional, eu não precisei refazer nenhuma das dimensões que já existiam. Criei apenas uma nova fato e uma junk, que agregava várias flags e voilà, tudo pronto.

Resumidamente, eu 1) construí o modelo DV, 2) construí o modelo da nova estrela, 3) gerei o ETL do DV automaticamente e 4) criei o ETL para estrela na mão. Levou um mês, mais ou menos, e eu produzi tudo com documentação e processo. Nada de improvisos – não gerei um único débito técnico. Tanto que eu fui embora e deixei-o rodando. Deixei-o não: eu esqueci completamente que ele existia.

Tudo Muda

Eu esqueci, mas o cliente não. Esse “remendo” está funcionando desde então, há mais de seis meses, diariamente, sem ter sofrido uma única parada causada pelo ETL do DV ou dali para o dimensional.


(…)sem ter sofrido UMA ÚNICA PARADA causada pelo ETL(…) Sabe, acabei de me tocar disso e estou profundamente impressionado. Caraca, NUNCA deu pau!! O ETL para o DV parou algumas vezes, mas sempre por causa de problemas gerais, como instabilidade de rede ou pau do banco, nunca por causa de erros imprevistos, e nunca teve nenhuma inconsistência de dados. :-O C-A-R-A-C-A!!…


Voltando: desde de o ano passado que esse ODS vem sendo desativado, pois ele é complexo demais e seu ETL sofre paradas demais (sem contar inconsistências de dados, quando o ETL vai até o final.) Uma nova iniciativa de DW corporativo foi montada (pfff…) e começaram de novo (eu já vi essa história antes…). Decidiram não fazer nenhum modelo: se antes o ODS fazia alguma integração, agora teríamos um palco persistente (PSA, de Persistent Staging Area.) A partir desse PSA as estrelas de consulta eram populadas. Ou seja, se antes a integração acontecia na entrada do ODS, agora ela acontece na saída do PSA. Enfim…

Como disse Otis, as coisas mudam, sempre mudam. Há uns dois meses chegou a hora de desativar o pedaço do ODS que servia de fonte para meu DV. Era preciso migrar o meu Data Vault do ODS para os sistemas de origem, e precisava ser uma migração à quente, sem parar de rodar e sem refazer nada. Não seria possível, por exemplo, analisar as tabelas dos sistemas de origem que compunham o ODS e refazer quaisquer hubs, links ou satélites.

Vem Quente…

A arquitetura após a migração da fonte ficaria assim:

Alteração de fonte do Data Vault.
Alteração de fonte do Data Vault.

Aqui há outro problema embutido: as tabelas que existem nesse ODS são quase as mesmas que existem nos sistemas de origem. Ou seja, se no sistema de origem existe uma tabela produto, no ODS vai existir uma tabela tb_pro_produto. Se essa tabela, na origem, possui 10 campos, no ODS vai possuir 9 ou 11 ou 30 campos. Grosso modo, porém, o conteúdo do sistema de origem existe no ODS quase intacto. Logo, para usarmos os sistemas de origem no lugar do ODS é preciso analisar a correspondência entre as tabelas.

Para cada tabela do ODS que o Data Vault consultava haviam três possibilidades:

  1. Equivalência direta: no máximo o nome da tabela (ou de uma de suas colunas) muda;
  2. Praticamente a mesma coisa: sem contar o nome da tabela, o conteúdo era praticamente o mesmo. As diferenças seriam um nome de coluna diferente, uma coluna a mais ou a menos, mas o mesmo grão: se na origem existissem 1000 registros, o ODS teriam 1000 registros, equivalentes um a um;
  3. Tabelas equivalentes: meu Data Vault usava uma tabela no ODS que era resultado da combinação de duas ou mais tabelas do sistema de origem.

O melhor caso é o primeiro, pois a mudança no Data Vault resumir-se-ia a trocar os parâmetros de conexão para apontar para o novo banco e, talvez, mudar um nome de tabela ou coluna.

O segundo caso também não seria difícil: para cada link, hub ou satélite que usasse esse tipo de tabela bastaria reescrever um único SQL, e mudar a conexão do ODS para o novo banco, e as transformações estariam migradas.

Já o terceiro caso seria o pior. Haveriam duas situações possíveis:

  1. A tabela equivalente dentro do ODS derivava de várias tabelas de uma única fonte de dados. Ou seja, é possível construir um SQL, ou talvez uma procedure mais complexa, que remonta a antiga tabela a partir das tabelas do sistema de origem. Esse novo e complexo SQL seria o novo SQL de cada transformação de hub, link ou satélite, que junto com a mudança de fonte de dados completaria a migração;
  2. A tabela equivalente dentro do ODS derivava de várias tabelas, de duas ou mais fontes de dados. Ou seja, como um SELECT (ordinariamente) não cruza as fronteiras de bancos, e muito menos de tecnologias de bancos, não seria possível construir um SQL para replicar a tabela do ODS. Seria necessário uma transformação intermediária, que unisse esses dados e entregasse-os para as transformações de carga de hubs, links e satélites.

Na pior das piores hipóteses, poderíamos criar uma tabela intermediária, em um palco, e usá-la para carregar o DV.


A migração de fonte de dados de um DV vai de algo tão simples como mudar um IP e uma senha, na conexão com um banco de dados de origem, a algo complexo e trabalhoso como reconstruir parte do DV ou criar etapas de carga intermediárias. Em qualquer situação, porém, sempre haverá uma saída e ela nunca vai quebrar o downstream, o lado do cliente.


…Que o DV Está Fervendo!

Fizemos – a equipe de desenvolvimento do DW e eu – uma áudio-conferência há umas três semanas atrás. Em menos de duas horas eu expliquei o que era DV, o básico de como se construir um e como o trecho do DV funcionava. Depois expliquei exatamente os mesmos pontos acima, mostrando que, quanto mais complexa for a origem do DV, maior vai ser o trabalho de migração.

Bom, o trabalho de migração (já!) acabou! O pior caso foi o de umas tabelas que combinavam coisas de um mesmo sistema, mas sem alterar o grão, de modo que mesmo o pior caso foi muito fácil de fazer.

Não estamos esquecendo de nada?…

Sim! E o data mart populado pelo DV? Você consegue chutar o que deve ter acontecido com ele, e com o ETL do DV para a estrela?

Simples, não aconteceu absolutamente nada. Veja, apenas alteramos as entradas do Data Vault, e nada mais. Assim, o ETL que rodava sobre o DV para popular a estrela que o cliente usava continuou como estava!!

Conclusão

Um Data Vault carrega grandes promessas:

  • Carregar 100% dos dados, 100% das vezes (regra de ouro do DV;)
  • Acomodar qualquer mudança dos sistemas de origem, sem quebrar;
  • Permitir exploração dos dados como o cliente quiser, sem quebrar;
  • Reduzir o trabalho de desenvolvimento e manutenção, automatizando sempre que possível;
  • Reduzir e até eliminar retrabalho;
  • Grande velocidade de carga.

O primeiro artigo, Como um Data Vault Evolui, mostrava o que acontece com um DV quando uma premissa inicial se mostrava incorreta, e como ele se acomoda elegantemente os ajustes necessários. Este post mostrou de que forma uma mudança profunda como a troca de fonte de dados é tratada por um DV. Ainda que tenhamos tido sorte com um ODS que não era complexo demais, todas as mudanças ocorreram em questão de semanas, sem quebrar o dia-a-dia do cliente.

E ele continua rodando sem parar há seis meses! :-D

Como um Data Vault Evolui

Ontem eu estava mexendo no meu projeto de DV de estimação (um aconselhamento que presto a um amigo) e descobri uma coisa: o satélite dos dados dos empregados tinha centenas de registros por empregado. Eu fui olhar de perto e descobri que não eram centenas, mas sim um por dia desde o início da captura dos dados. Para um DV, isso significa que a cada refresh (que é diário neste caso) o ETL está versionando o satélite de empregados. Como isso só aconteceria se todo dia houvesse alguma diferença para a última versão, eu decidi analisar os registros, comparando as versões de satélites para um empregado qualquer.

Eu vou mostrar algumas imagens para ilustrar o que eu fiz, mas saibam que todos os nomes foram mudados para coisas mais óbvias, e campos particulares (que possuíam detalhes da arquitetura do sistema) foram removidos. São ilustrações, não são o caso real, ok? Exceto por esse detalhe, todo o restante é a narração fiel do que eu fiz.

O satélite Empregado, mostrado na figura abaixo junto ao hub Empregado, tem cerca de 13 campos do sistema de origem, mais 4 de controle do DV.

Satélite empregado original, com todos os campos em uma única tabela.
Satélite empregado original, com todos os campos em uma única tabela.

Todos esses campos estão em uma única tabela no sistema de origem, de modo que a carga desse pedaço do modelo é feito por duas transformações: uma de hub e uma de satélite.

Eu descobri, depois de analisar o conteúdo do satélite, que três campos eram atualizados sempre que o empregado chegava para trabalhar e depois ia embora:

  • emp_ultimo_acesso
  • emp_ultimo_ip
  • emp_ultima_sessao

Na verdade, sempre que o empregado fazia login (e depois logoff) em qualquer computador na empresa, esses detalhes são atualizados. Resultado: todo dia eles estavam diferentes do dia anterior, a menos que o empregado tivesse faltado, ou o dia anterior fosse um feriado/fim-de-semana. Portanto, todo dia um novo satélite era carregado, e isso estava correto. O ETL estava fazendo o que havia sido programado para fazer.

Satélites Separados

Temos aqui uma situação clássica para Data Vault: o sistema de origem tem taxas de atualização diferente entre os atributos. Alguns são atualizados uma vez na vida e outra na morte, e outros são alterados todos os dias, quando não várias vezes por dia. Se capturarmos todos os registros na mesma tabela estaremos desperdiçando tempo e espaço em disco, tratando e gravando coisas duplicadas, desnecessariamente.

Neste caso optamos por quebrar um satélite em dois ou mais, em função de sua taxa de atualização: um satélite conterá apenas os três campos que mudam todos os dias, e o outro satélite ficará com os campos mais estáveis. Cada um terá sua própria transformação para carga. No final, nosso DV vai ficar assim:

Satélite Empregado, agora quebrado em duas tabelas em função da taxa de atualização.
Satélite Empregado, agora quebrado em duas tabelas em função da taxa de atualização.

Aplicando a Mudança

Antes havia um satélite (=uma tabela), com todos os campos, carregada por uma transformação. Depois teremos duas tabelas, cada qual com seu conjunto de campos, e cada qual carregada por sua transformação. Eis o passo-a-passo que eu passei para meu amigo aplicar em produção:

  1. Renomear o satélite original para s_empregado_antigo;
  2. Criar as duas novas tabelas, s_empregado e s_empregado_1;
  3. Popular cada uma com o histórico atual;
  4. Apagar o satélite original;
  5. Subir as duas novas transformações.

As novas tabelas foram criadas e populadas de uma só vez com um SELECT INTO (o DV está em Postgres, o que facilita tudo.) As transformações foram criadas semi-automaticamente (basta entrar os nomes das tabelas, campos e da transformação e um script parametrizado gera tudo sozinho.)

Pronto! Quinze minutos depois de diagnosticar o problema eu tinha desenhado a solução. Meu amigo avisou que aplicou e deu tudo certo e agora vai propagar a solução para outros satélites (ele tem vários desses com status instantâneo.)

(Bom, vá lá, eu demorei um pouco mais que quinze minutos porque deu um trabalhinho até eu acertar o SELECT – ele precisava manter o histórico, o que significa dois SELECT DISTINCTs, com ORDER BY etc. Mas agora eu já sei o macete, e da próxima vez vai ser só 15min mesmo!)

Outras Quebras

Outras opções de quebras para satélites são por sistema de origem, que dá a vantagem de integrar os dados já no DV, e por particionamento. Neste último podemos deslocar satélites estáveis para outras mídias (outros tablespaces), e continuar a carregar os novos em uma tabela menor.

O Que Kimball Faria?

Meu grande amigo Gurgel que me perdoe, mas eu não vou nem considerar essa situação na 3NF. Agora, como ficaria essa situação em um Modelo Dimensional?

Na verdade, ficaria muito bem, obrigado! Veja, Modelagem Dimensional é uma técnica resiliente e robusta, com muita flexibilidade. Teríamos praticamente a mesma abordagem: quebrar uma tabela (de dimensão) em duas, criar dois novos processos de cargas (duas novas transformações), e recriar a fato, agora com duas chaves no lugar de uma só.

Factível, viável e simples, sim. Interessante? Não tenho certeza: hoje esses dados não possuem nenhum interesse para o negócio do meu amigo. São dados que ele descartaria sem pensar duas vezes – e foi essa a primeira sugestão dele. Saber qual é a hora do último logoff de cada empregado não tem o menor impacto no rendimento da empresa, nem a menor relação com a produtividade desse empregado. É um dado pura e simplesmente inútil, e só entrou no satélite porque simplificamos o levantamento de requisitos ao mínimo essencial – o também clássico carrega tudo!.

O Que Linstedt Faria?

Tá bom, saber quando o empregado fez o último logoff do dia é inútil. Mas e saber o histórico completo de todos os logins e logoffs, interessa?

Veja, estamos falando de capturar todas as mudanças, até mesmo em tempo real se for necessário. Para conseguir isso, sem gastar muito, basta rodar apenas a transformação que carrega esse satélite (com um ajuste para a variável de tempo – detalhes que não vêm ao caso agora…) a cada hora ou minuto. Com algumas centenas de empregados esse processo seria muito leve.

No caso mais extremo, dá para agendar uma PROC no banco que faça isso, e descartar o PDI completamente, reduzindo ainda mais o impacto da captura de histórico.

Com esses dados, novas perguntas são possíveis:

  • Será que um empregado que entra e sai do sistema várias vezes produz menos?
  • Preciso me preocupar com isso?

Um modelo dimensional permite capturar isso se você quiser. Basta montar uma estrela só para isso, já que esse vai ser o processo de negócio em análise.

Agora, e aqui vem uma das coisas legais do DV, um Data Vault te permite capturar isso já integrado com os outros satélites, o hub e tudo o mais. Um bom desenhista dimensional sabe que a técnica do Kimball também te dá essa possibilidade. Mas quanto mais você extende seu DW Dimensional com esse tipo de recurso, mais chega perto de um modelo Data Vault! A quantidade de dimensões e inter-relações (o Bus Matriz) começa a crescer, e a gestão vai ficando cada vez mais difícil. Apesar de flexível, a Modelagem Dimensional não é pensada para acumular dados, mas para análisá-los e por isso, cedo ou tarde, se seu DW muda com frequẽncia, um DV vai se tornar uma alternativa interessante.

E então você vai testar, só para ver como seria. E, então, já será tarde demais. Você será fisgado, como eu fui.

Até a próxima! Fui! :-)

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! ;-)

Acesso ao Log do BI Server, Quick & Dirt Parte 2 – Usando XActions

No post anterior eu mostrei como implementar a genial idéia do Gerson Tessler para acessar os logs do BI Server via o próprio BI Server usando um relatório PRD e uma transformação. Agora vamos ver outra técnica (que eu prefiro porque tem um overhead menor): como expor o log do BI Server (ou qualquer outro) usando a mesma transformação e uma XAction.

Primeiro você precisa instalar e configurar o Pentaho Design Studio. Acesse a página de links do site companheiro do livro Pentaho na Prática e baixe o capítulo de degustação. Olhe nas páginas 3, 5 e 17 como instalar o PDS. Depois baixe este guia rápido e configure um projeto para seu BI Server 4.8. Teste e brinque um pouco com o BI Server e o PDS, até sacar a mecânica da coisa (atualizações feitas com o PDS sobre XACTIONs aparecem no BI Server depois de um refresh do repositório, a menos que você use um repositório em arquivo.)

Pronto? Vamos lá:

  1. No PDS clique com o botão da direita sobre a Beltrano e escolha a opção BI Platform e depois New Action Sequence;
  2. Na janela que aparecer deixe o campo Container como está e modifique o nome no campo File name de untiltled.xaction para log.xaction;
  3. Aba General: não mexa em nada e pule para a aba seguinte, Define Process;
  4. Na aba Define Process clique no ícone de mais azul que fica na seção Process Actions. Vai se abrir um menu: escolha Get Data From e depois Pentaho Data Integration;
  5. Usando a Figura 1 como guia, preencha:
    1. Name: não precisa mudar nada;
    2. Input Section: Transformation File deve apontar para a transformação (preencha com solution:le_log_biserver.ktr ou use o botão Browse – mas ele nunca funciona comigo…). Depois digite em Transformation Step o nome do passo que o BI Server deve drenar para receber as linhas lidas pela transformação, que é Saida;
    3. Output Section: preencha apenas o campo Output Rows Name com resultado, que é um nome da variável para receber as linhas drenadas da transformação;
  6. Para “imprimir” o que foi lido, adicione a variável resultado à seção Process Outputs (basta clicar no ícone de mais azul e selecioná-la).
Figura 1: configurando a execução de uma transformação no PDS. (Clique para tamanho natural.)
Figura 1: configurando a execução de uma transformação no PDS. (Clique para tamanho natural.)

E está pronto. Salve a XAction, mude para o BI Server, faça login, depois um refresh do repositório. A Xaction deve aparecer – execute-a com um duplo clique. Se tudo deu certo você vai ver o mesmo resultado do post anterior, feito com PRD, mas agora sem a “cara” de um relatório (Figura 2.)

Figura 2: exibindo o log do BI Server com XAction e transformação. (Clique para tamanho natural.)
Figura 2: exibindo o log do BI Server com XAction e transformação. (Clique para tamanho natural.)

Como da outra vez você pode baixar o pacote no site do Open BI Solutions: https://sourceforge.net/projects/openbisolutions/files/Logs/.

Até a próxima!

Acesso ao Log do BI Server, Quick & Dirt

Qualquer desenvolvedor de soluções com o BI Server precisa ter acesso ao(s) log(s). Na maioria das empresas os desenvolvedores simplesmente têm acesso direto ao BI Server e podem examinar os arquivos de log diretamente. Em outras empresas, porém, isso não é possível – não me pergunte porquê, mas existem empresas nas quais o desenvolvedor é proibido de acessar o ambiente de desenvolvimento. De produção, então, nem pensar!

Gerson Tessler, meu colega de trabalho e amigo, que mexe com Pentaho desde 2008, deu uma solução genial para esses desenvolvedores desafortunados: usar o próprio BI Server para examinar qualquer log. Fácil, simples, óbvio – a marca da genialidade!

Vamos fazer como um laboratório:

  1. Monte um BI Server e remova as pastas de demonstração;
  2. Crie uma pasta vazia. Como eu sempre uso a Beltrano S/A para tudo, minha pasta se chamará Beltrano;
  3. Abra o PDI e crie a transformação da Figura 1 (adicione um passo Text File Input e um Dummy, ligando o primeiro ao segundo):

    Figura 1: Layout de passos da transformação.
    Figura 1: Layout de passos da transformação. (Clique para tamanho normal.)
  4. Configure o Text File Input:
    1. Insira ${Internal.Transformation.Filename.Directory}/../../tomcat/logs/pentaho.log no campo File/Directory da seção Selected Files, aba File (Figura 2);

      Figura 2: configurando o arquivo. (Clique para tamanho normal.)
      Figura 2: Configurando o arquivo. (Clique para tamanho normal.)
    2. Aba Content (Figura 3), campo Filetype: CSV; campo Separator: §§§ (ou qualquer coisa que dificilmente aparecerá no log); desligar o checkbox Header; Format Unix (Linux e Mac) ou DOS (Windows); Encoding UTF-8;

      Figura 3: configurando a interpretação do arquivo. (Clique para tamanho normal.)
      Figura 3: Configurando a interpretação do arquivo. (Clique para tamanho normal.)
    3. Aba Fields (ignore todas as outras): registre um campo chamado log_line como Type String, deixando todos os outros parâmetros vazios.
  5. Dummy: apenas mude o nome para Saida (sem acento);
  6. Salve dentro da pasta Beltrano, em ./biserver-ce/pentaho-solutions/Beltrano.

Essa transformação vai ler o arquivo de log independentemente de onde estiver o BI Server, porque se refere ao arquivo de maneira relativa, apontando para o ./tomcat/logs a partir de dois diretórios acima do pentaho-solutions /beltrano. (Nota: talvez no Windows seja preciso reverter a barra, mas teste antes.)

Segunda parte: executando a transformação a partir do BI Server, para o qual temos duas opções. A primeira e mais trivial é usando um relatório criado com o PRD:

  1. Rode o PRD e crie um novo relatório e salve-o (já, senão pode dar erro) na mesma pasta da transformação, ou seja, na Beltrano dentro do BI Server;
  2. Clique com o botão da direita no cilindro amarelo (aba Data) e selecione Pentaho Data Integration;
  3. Na janela que se abrirá (Figura 4) clique em Browse e selecione a transformação – que deve estar no mesmo diretório;

    Selecionando uma transformação como fonte do relatório.
    Figura 4: Selecionando uma transformação como fonte do relatório.
  4. No que a janela de seleção se fechar, os passos da transformação serão listados. Clique em Saida e depois em Ok;
  5. Voltamos à lona, para construir o relatório (Figura 5). Sem estresse: arraste o campo log_field para a banda Details;

    Posicionando e configurando o campo. (Clique para tamanho natural.)
    Figura 5: Posicionando e configurando o campo. (Clique para tamanho natural.)
  6. Posicione o campo no extremo esquedo e alargue-o até ocupar a folha inteira;
  7. Com o campo selecionado, mude para a aba Structure, sub-aba Style. Localize a propriedade Dynamic Height e sete-a para TRUE;
  8. Para ficar bonito, acesse o menu File, opção Report Properties (e aba Descriptio na janela que se abrir) e preencha o título (algo como “Log”, mas sem as aspas… ;-) );
  9. Salve, faça login no BI Server, comande um refresh e execute o relatório.

Se tudo deu certo vai aparecer a Figura 6:

Examinando o log do BI Server via relatório dentro do BI Server.
Examinando o log do BI Server via relatório dentro do BI Server.

Veja que estamos acessando um dos arquivos do diretório de logs do BI Server e que podemos usar o mesmo método para qualquer arquivo. Não apenas isso, mas como estamos usando uma transformação em um relatótio, podemos combinar as capacidades dos dois e adicionar (por exemplo), filtros por data e hora, horizonte (quanto do log mostrar) etc.

A outra maneira é rodando uma XAction, que eu vou publicar em em 15/8/13. Até lá você pode obter o pacote relatório + transformação no site de projetos de BI livres: https://sourceforge.net/projects/openbisolutions/files/Logs/. Basta descompactar o arquivo dentro do seu pentaho-solutions/Beltrano (ou qualquer outra pasta) e atualizar seu BI Server. Deixe um comentário aqui se tiver algum problema.

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.