A modelagem dimensional é uma abordagem comprovada para a construção de data warehouses prontos para anÔlises. Embora muitas organizações estejam migrando para plataformas modernas como Databricks, essas técnicas fundamentais ainda se aplicam.
Na Parte 1, nós projetamos nosso esquema dimensional. Na Parte 2, nós construĆmos pipelines ETL para tabelas de dimensĆ£o. Agora na Parte 3, implementamos a lógica ETL para tabelas de fatos, enfatizando eficiĆŖncia e integridade.
Em o primeiro blog, definimos a tabela de fatos, FactInternetSales, conforme mostrado abaixo. Em comparação com nossas tabelas de dimensões, a tabela de fatos é relativamente estreita em termos de comprimento do registro, com apenas referências de chave estrangeira para nossas tabelas de dimensões, nossas medidas de fatos, nossos campos de dimensão degenerada e um único campo de metadados presente:
NOTA: No exemplo abaixo, alteramos a declaração CREATE TABLE do nosso primeiro post para incluir as definiƧƵes de chave estrangeira em vez de defini-las em declaraƧƵes ALTER TABLE separadas. TambĆ©m incluĆmos uma restrição de chave primĆ”ria nos campos de dimensĆ£o degenerada para ser mais explĆcito sobre o papel deles nesta tabela de fatos.
A definição da tabela é bastante direta, mas vale a pena discutir o LastModifiedDateTime campo de metadados. Embora as tabelas de fatos sejam relativamente estreitas em termos de contagem de campos, elas tendem a ser muito profundas em termos de contagem de linhas. As tabelas de fatos geralmente abrigam milhões, se não bilhões, de registros, muitas vezes derivados de atividades operacionais de alto volume. Em vez de tentar recarregar a tabela com uma extração completa em cada ciclo ETL, normalmente limitamos nossos esforços a novos registros e aqueles que foram alterados.
Dependendo do sistema de origem e de sua infraestrutura subjacente, existem muitas maneiras de identificar quais registros operacionais precisam ser extraĆdos em um determinado ciclo ETL. As capacidades de captura de dados de alteração (CDC) implementadas no lado operacional sĆ£o os mecanismos mais confiĆ”veis. Mas quando esses nĆ£o estĆ£o disponĆveis, geralmente recorremos a timestamps registrados com cada registro de transação Ć medida que Ć© criado e modificado. A abordagem nĆ£o Ć© Ć prova de falhas para detecção de alteraƧƵes, mas como qualquer desenvolvedor ETL experiente atestarĆ”, muitas vezes Ć© o melhor que temos.
NOTA: A introdução do Lakeflow Connect oferece uma opção interessante para realizar a captura de dados de alteração em bancos de dados relacionais. Esta capacidade estÔ em pré-visualização no momento da escrita deste blog. No entanto, à medida que a capacidade amadurece para expandir mais e mais RDBMSs, esperamos que isso forneça um mecanismo eficaz e eficiente para extrações incrementais.
Em nossa tabela de fatos, o LastModifiedDateTime campo captura um valor de timestamp registrado no sistema operacional. Antes de extrair dados de nosso sistema operacional, revisaremos a tabela de fatos para identificar o valor mais recente para este campo que registramos. Esse valor serÔ o ponto de partida para nossa extração incremental (também conhecida como delta).
O fluxo de trabalho de alto nĆvel para nosso ETL de fatos procederĆ” da seguinte maneira:
Para tornar esse fluxo de trabalho mais fÔcil de compreender, descreveremos suas fases-chave nas seções a seguir. Ao contrÔrio do post sobre ETL de dimensão, implementaremos nossa lógica para este fluxo de trabalho usando uma combinação de SQL e Python, dependendo de qual linguagem torna cada etapa mais fÔcil de implementar. Novamente, uma das forças da Plataforma Databricks é seu suporte para múltiplos idiomas. Em vez de apresentÔ-lo como uma escolha de tudo ou nada feita no topo de uma implementação, mostraremos como os engenheiros de dados podem alternar rapidamente entre os dois dentro de uma única implementação.
Os dois primeiros passos do nosso fluxo de trabalho se concentram em extrair novas informações e informações recentemente atualizadas do nosso sistema operacional. No primeiro passo, fazemos uma simples busca do último valor registrado para LastModifiedDateTime. Se a tabela de fatos estiver vazia, como deveria estar na inicialização, definimos um valor padrão que estÔ suficientemente no passado para acreditarmos que capturarÔ todos os dados relevantes no sistema de origem:
Agora podemos extrair os dados necessÔrios do nosso sistema operacional usando esse valor. Embora esta consulta inclua bastante detalhe, concentre sua atenção na clÔusula WHERE, onde empregamos o último valor de timestamp observado do passo anterior para recuperar os itens de linha que são novos ou modificados (ou associados a pedidos de venda que são novos ou modificados):
Como antes, os dados extraĆdos sĆ£o persistidos em uma tabela em nosso esquema de staging, acessĆvel apenas aos nossos engenheiros de dados, antes de prosseguir para as etapas subsequentes no fluxo de trabalho. Se tivermos qualquer limpeza de dados adicional a realizar, devemos fazĆŖ-lo agora.
A sequĆŖncia tĆpica em um ciclo ETL de data warehouse Ć© executar nossos fluxos de trabalho ETL de dimensĆ£o e depois nossos fluxos de trabalho de fatos logo em seguida.Ā Ao organizar nossos processos desta maneira, podemos garantir melhor que todas as informaƧƵes necessĆ”rias para conectar nossos registros de fatos aos dados de dimensĆ£o estarĆ£o disponĆveis.Ā No entanto, existe uma janela estreita dentro da qual novos dados orientados Ć dimensĆ£o chegam e sĆ£o capturados por um registro transacional relevante para fatos.Ā Essa janela aumenta se tivermos uma falha no ciclo ETL geral que atrasa a extração de dados de fatos.Ā E, claro, sempre podem haver falhas referenciais nos sistemas de origem que permitem que dados questionĆ”veis apareƧam em um registro transacional.
Para nos protegermos deste problema, inseriremos em uma determinada tabela de dimensão quaisquer valores de chave de negócio encontrados em nossos dados de fatos em estÔgio, mas não no conjunto de registros atuais (não expirados) para essa dimensão. Esta abordagem criarÔ um registro com uma chave de negócio (natural) e uma chave substituta que nossa tabela de fatos pode referenciar. Esses registros serão marcados como chegando tarde se a dimensão alvo for um SCD do Tipo-2, para que possamos atualizar adequadamente no próximo ciclo ETL.
Para começar, vamos compilar uma lista de campos de negócios chave em nossos dados de staging. Aqui, estamos explorando convenções de nomenclatura estritas que nos permitem identificar esses campos dinamicamente:
NOTA: Estamos mudando para Python nos próximos exemplos de código. Databricks suporta o uso de vĆ”rias linguagens, mesmo dentro do mesmo fluxo de trabalho. Neste exemplo, Python nos dĆ” um pouco mais de flexibilidade enquanto ainda se alinha com os conceitos de SQL, tornando essa abordagem acessĆvel para mais desenvolvedores SQL tradicionais.Ā
Note que separamos nossas chaves de data das outras chaves de negócios. Voltaremos a essas em um momento, mas por agora, vamos nos concentrar nas chaves não-datadas (outras) nesta tabela.
Para cada chave de negócio que nĆ£o seja data, podemos usar nossas convenƧƵes de nomenclatura de campo e tabela para identificar a tabela de dimensĆ£o que deve conter essa chave e, em seguida, realizar um left-semi join (semelhante a uma comparação NOT IN() mas suportando correspondĆŖncia de vĆ”rias colunas, se necessĆ”rio) para identificar quaisquer valores para essa coluna na tabela de staging, mas nĆ£o na tabela de dimensĆ£o. Quando encontramos um valor nĆ£o correspondido, simplesmente o inserimos na tabela de dimensĆ£o com a configuração apropriada para o IsLateArriving campo:Ā
Esta lógica funcionaria bem para nossas referĆŖncias de dimensĆ£o de data se quisĆ©ssemos garantir que nossos registros de fatos estejam vinculados a entradas vĆ”lidas.Ā No entanto, muitos sistemas de BI downstream implementam lógica que requer que a dimensĆ£o de data abrigue uma sĆ©rie contĆnua e ininterrupta de datas entre os valores mais antigos e mais recentes registrados.Ā Caso encontremos uma data antes ou depois do intervalo de valores na tabela, precisamos nĆ£o apenas inserir o membro ausente, mas criar os valores adicionais necessĆ”rios para preservar um intervalo ininterrupto.Ā Por esse motivo, precisamos de uma lógica ligeiramente diferente para quaisquer datas de chegada tardia:
Se vocĆŖ nĆ£o trabalhou muito com Databricks ou Spark SQL, a consulta no coração deste Ćŗltimo passo provavelmente Ć© estranha. A sequence() função cria uma sequĆŖncia de valores com base em um inĆcio e fim especificados. O resultado Ć© uma matriz que podemos entĆ£o explodir (usando a explode() função) para que cada elemento na matriz forme uma linha em um conjunto de resultados. A partir daĆ, simplesmente comparamos o intervalo necessĆ”rio com o que estĆ” na tabela de dimensĆ£o para identificar quais elementos precisam ser inseridos. Com essa inserção, garantimos que temos um valor de chave substituta implementado nesta dimensĆ£o como uma smart key para que nossos registros de fatos tenham algo para referenciar.Ā
Agora que podemos ter certeza de que todas as chaves de negócio em nossa tabela de staging podem ser correspondidas a registros em suas dimensões correspondentes, podemos prosseguir com a publicação na tabela de fatos.
O primeiro passo neste processo é procurar os valores de chave estrangeira para essas chaves de negócio. Isso pode ser feito como parte de um único passo de publicação, mas o grande número de junções na consulta muitas vezes torna essa abordagem desafiadora para manter. Por esse motivo, podemos adotar a abordagem menos eficiente, mas mais fÔcil de compreender e modificar, de procurar valores de chave estrangeira um negócio de cada vez e anexar esses valores à nossa tabela de staging:
Novamente, estamos explorando convenções de nomenclatura para tornar essa lógica mais fÔcil de implementar. Como nossa dimensão de data é uma dimensão de papel e, portanto, segue uma convenção de nomenclatura mais variÔvel, implementamos uma lógica ligeiramente diferente para essas chaves de negócios.
Neste ponto, nossa tabela de staging abriga chaves de negócio e valores de chave substituta, juntamente com nossas medidas, campos de dimensĆ£o degenerada e o valor LastModifiedDate extraĆdo do nosso sistema de origem. Para tornar a publicação mais gerenciĆ”vel, devemos alinhar os campos disponĆveis com os suportados pela tabela de fatos. Para fazer isso, precisamos descartar as chaves de negócio:
NOTA: O source dataframe é definido no bloco de código anterior.
Com os campos alinhados, a etapa de publicação é simples. Comparamos nossos registros de entrada com os da tabela de fatos com base nos campos de dimensão degenerada, que servem como um identificador único para nossos registros de fatos, e então atualizamos ou inserimos valores conforme necessÔrio:
Esperamos que esta sĆ©rie de blog tenha sido informativa para aqueles que buscam construir modelos dimensionais na Plataforma Databricks.Ā Esperamos que muitos experientes com essa abordagem de modelagem de dados e os fluxos de trabalho ETL associados a ela achem o Databricks familiar, acessĆvel e capaz de suportar padrƵes estabelecidos hĆ” muito tempo com mĆnimas alteraƧƵes em comparação com o que pode ter sido implementado em plataformas RDBMS. Onde surgem mudanƧas, como a capacidade de implementar lógica de fluxo de trabalho usando uma combinação de Python e SQL, esperamos que os engenheiros de dados achem que isso torna seu trabalho mais direto para implementar e suportar ao longo do tempo.
Para saber mais sobre Databricks SQL, visite nosso website ou leia a documentação. VocĆŖ tambĆ©m pode conferir o tour do produto para Databricks SQL. Suponha que vocĆŖ queira migrar seu armazĆ©m existente para um data warehouse sem servidor de alto desempenho, com uma ótima experiĆŖncia do usuĆ”rio e custo total mais baixo. Nesse caso, Databricks SQL Ć© a solução ā experimente gratuitamente.
Ā
(This blog post has been translated using AI-powered tools) Original Post
Produto
June 12, 2024/11 min de leitura

