Outil de création de données ou ce qui est commun entre un entrepôt de données et un smoothie


Quels sont les principes d'un Data Warehouse idéal?

Concentrez-vous sur la valeur commerciale et l'analyse en l'absence de code standard. Gestion de DWH en tant que base de code: versionnage, révision, tests automatisés et CI. Modularité, extensibilité, open source et communauté. Documentation utilisateur conviviale et visualisation des dépendances (Data Lineage).

En savoir plus sur tout cela et sur le rôle de DBT dans l'écosystème Big Data & Analytics - Bienvenue chez cat.

Bonjour Ă  tous


En contact avec Artemy Kozyr. Depuis plus de 5 ans, je travaille avec des entrepôts de données, la construction d'ETL / ELT, ainsi que l'analyse et la visualisation de données. Je travaille actuellement chez Wheely , enseigne à OTUS sur le cours Data Engineer , et aujourd'hui je veux partager avec vous un article que j'ai écrit la veille du début d'une nouvelle inscription au cours .

Bref avis


Le cadre DBT est tout au sujet de la lettre T dans l'acronyme ELT (Extract - Transform - Load).

Avec l'avènement de bases de donnĂ©es analytiques productives et Ă©volutives telles que BigQuery, Redshift, Snowflake, tout sens de faire des transformations en dehors de l'entrepĂ´t de donnĂ©es a disparu. 

DBT ne décharge pas les données des sources, mais offre d'énormes possibilités de travailler avec des données déjà chargées dans le stockage (dans le stockage interne ou externe).


Le but principal de DBT est de prendre le code, de le compiler en SQL, d'exécuter les commandes dans le bon ordre dans le référentiel.

Structure du projet DBT


Le projet se compose de répertoires et de fichiers de seulement 2 types:

  • Modèle (.sql) - unitĂ© de transformation exprimĂ©e par une requĂŞte SELECT
  • Fichier de configuration (.yml) - paramètres, rĂ©glages, tests, documentation

Au niveau de base, le travail est structuré comme suit:

  • L'utilisateur prĂ©pare le code du modèle dans n'importe quel IDE pratique
  • Ă€ l'aide de la CLI, les modèles sont lancĂ©s, DBT compile le code du modèle en SQL
  • Le code SQL compilĂ© est exĂ©cutĂ© dans l'entrepĂ´t dans la sĂ©quence spĂ©cifiĂ©e (graphique)

Voici Ă  quoi pourrait ressembler le lancement Ă  partir de la CLI:


Tout est SELECT


Il s'agit d'une fonctionnalité de tueur du cadre de l'outil de génération de données. En d'autres termes, DBT résume tout le code lié à la matérialisation de vos requêtes dans l'entrepôt (variations des commandes CREATE, INSERT, UPDATE, DELETE ALTER, GRANT, ...).

Tout modèle implique l'écriture d'une requête SELECT, qui définit l'ensemble de données résultant.

Dans le même temps, la logique de transformation peut être à plusieurs niveaux et consolider les données de plusieurs autres modèles. Un exemple de modèle qui va construire une vitrine de commandes (f_orders):

{% set payment_methods = ['credit_card', 'coupon', 'bank_transfer', 'gift_card'] %}
 
with orders as (
 
   select * from {{ ref('stg_orders') }}
 
),
 
order_payments as (
 
   select * from {{ ref('order_payments') }}
 
),
 
final as (
 
   select
       orders.order_id,
       orders.customer_id,
       orders.order_date,
       orders.status,
       {% for payment_method in payment_methods -%}
       order_payments.{{payment_method}}_amount,
       {% endfor -%}
       order_payments.total_amount as amount
   from orders
       left join order_payments using (order_id)
 
)
 
select * from final

Quelles choses intéressantes pouvons-nous voir ici?

Premièrement: les expressions CTE (Common Table Expressions) sont utilisées pour organiser et comprendre le code qui contient de nombreuses transformations et la logique

métier.Deuxièmement: Le code du modèle est un mélange de SQL et du langage Jinja (langage de modèle ).

Dans l'exemple, la boucle for a été utilisée pour former le montant pour chaque mode de paiement spécifié dans l'expression définie . La fonction ref est également utilisée - la possibilité de se référer à l'intérieur du code à d'autres modèles:

  • Au moment de la compilation, ref sera converti en un pointeur cible vers une table ou une vue dans le rĂ©fĂ©rentiel
  • ref vous permet de construire un graphe des dĂ©pendances du modèle

C'est Jinja qui ajoute des possibilités presque illimitées à DBT. Les plus utilisés:

  • Instructions if / else - instructions de branchement
  • Pour boucles - boucles
  • Variables - Variables
  • Macro - CrĂ©er des macros

Matérialisation: table, vue, incrémentielle


Stratégie de matérialisation - une approche selon laquelle l'ensemble de données de modèle résultant sera stocké dans le référentiel.

Dans une considération de base, c'est:

  • Table - table physique dans le stockage
  • Vue - vue, table virtuelle dans le rĂ©fĂ©rentiel

Il existe des stratégies de matérialisation plus complexes:

  • IncrĂ©mentiel - chargement incrĂ©mentiel (grandes tables de faits); de nouvelles lignes sont ajoutĂ©es, celles modifiĂ©es sont mises Ă  jour, celles supprimĂ©es sont effacĂ©es 
  • ÉphĂ©mère - le modèle ne se matĂ©rialise pas directement, mais participe en tant que CTE dans d'autres modèles
  • Toutes autres stratĂ©gies que vous pouvez ajouter vous-mĂŞme

En plus des stratégies de matérialisation, des opportunités sont ouvertes pour l'optimisation pour des entrepôts spécifiques, par exemple:

  • Flocon de neige : tables transitoires, comportement de fusion, regroupement de tables, copie de subventions, vues sĂ©curisĂ©es
  • Redshift : Distkey, Sortkey (entrelacĂ©, composĂ©), vues Ă  liaison tardive
  • BigQuery : partitionnement et clustering de table, comportement de fusion, chiffrement KMS, Ă©tiquettes et balises
  • Spark : format de fichier (parquet, csv, json, orc, delta), partition_by, clustered_by, buckets, incremental_strategy

Les référentiels suivants sont actuellement pris en charge:

  • Postgres
  • Redshift
  • Bigquery
  • Flocon de neige
  • Presto (partiellement)
  • Étincelle (partiellement)
  • Microsoft SQL Server (adaptateur de communautĂ©)

Améliorons notre modèle:

  • Rendre son remplissage incrĂ©mental (incrĂ©mental)
  • Ajouter des clĂ©s de segmentation et de tri pour Redshift

--  : 
--  ,      (unique_key)
--   (dist),   (sort)
{{
  config(
       materialized='incremental',
       unique_key='order_id',
       dist="customer_id",
       sort="order_date"
   )
}}
 
{% set payment_methods = ['credit_card', 'coupon', 'bank_transfer', 'gift_card'] %}
 
with orders as (
 
   select * from {{ ref('stg_orders') }}
   where 1=1
   {% if is_incremental() -%}
       --        
       and order_date >= (select max(order_date) from {{ this }})
   {%- endif %} 
 
),
 
order_payments as (
 
   select * from {{ ref('order_payments') }}
 
),
 
final as (
 
   select
       orders.order_id,
       orders.customer_id,
       orders.order_date,
       orders.status,
       {% for payment_method in payment_methods -%}
       order_payments.{{payment_method}}_amount,
       {% endfor -%}
       order_payments.total_amount as amount
   from orders
       left join order_payments using (order_id)
 
)
 
select * from final

Graphique de dépendance du modèle


C'est un arbre de dépendances. Il est DAG (Directed Acyclic Graph - Directional Acyclic Graph).

DBT construit un graphique basé sur la configuration de tous les modèles de projet, ou plutôt des liens ref () à l'intérieur des modèles vers d'autres modèles. Avoir un graphique vous permet de faire les choses suivantes:

  • ExĂ©cution de modèles dans le bon ordre
  • ParallĂ©lisation de l'habillage des fenĂŞtres
  • ExĂ©cution d'un sous-graphique arbitraire 

Exemple de visualisation de graphique:


Chaque nœud du graphe est un modèle, les bords du graphe sont donnés par l'expression ref.

Qualité des données et documentation


En plus de la formation des modèles eux-mêmes, DBT vous permet de tester un certain nombre d'assertions sur l'ensemble de données résultant, telles que:

  • Non nul
  • Unique
  • IntĂ©gritĂ© de rĂ©fĂ©rence - intĂ©gritĂ© de rĂ©fĂ©rence (par exemple, customer_id dans le tableau des commandes correspond Ă  l'id dans le tableau des clients)
  • Liste valide correspondante

Vous pouvez ajouter vos propres tests (tests de données personnalisés), tels que, par exemple,% d'écart de revenus avec des indicateurs il y a un jour, une semaine ou un mois. Toute hypothèse formulée comme une requête SQL peut être un test.

De cette façon, les écarts et erreurs indésirables dans les données peuvent être détectés dans la vitrine du stockage.

En termes de documentation, DBT fournit des mĂ©canismes pour ajouter, versionner et distribuer des mĂ©tadonnĂ©es et des commentaires au niveau du modèle et mĂŞme des attributs. 

Voici Ă  quoi ressemble l'ajout de tests et de documentation au niveau du fichier de configuration:

 - name: fct_orders
   description: This table has basic information about orders, as well as some derived facts based on payments
   columns:
     - name: order_id
       tests:
         - unique #    
         - not_null #    null
       description: This is a unique identifier for an order
     - name: customer_id
       description: Foreign key to the customers table
       tests:
         - not_null
         - relationships: #   
             to: ref('dim_customers')
             field: customer_id
     - name: order_date
       description: Date (UTC) that the order was placed
     - name: status
       description: '{{ doc("orders_status") }}'
       tests:
         - accepted_values: #    
             values: ['placed', 'shipped', 'completed', 'return_pending', 'returned']

Et voici à quoi ressemble cette documentation sur le site Web généré:


Macros et modules


Le but de DBT n'est pas tant de devenir un ensemble de scripts SQL, mais de fournir aux utilisateurs des outils puissants et riches en fonctionnalités pour construire leurs propres transformations et distribuer ces modules.

Les macros sont des ensembles de constructions et d'expressions qui peuvent être appelées comme fonctions dans les modèles. Les macros vous permettent de réutiliser le SQL entre les modèles et les projets conformément au principe d'ingénierie DRY (Don't Repeat Yourself).

Exemple de macro:

{% macro rename_category(column_name) %}
case
 when {{ column_name }} ilike  '%osx%' then 'osx'
 when {{ column_name }} ilike  '%android%' then 'android'
 when {{ column_name }} ilike  '%ios%' then 'ios'
 else 'other'
end as renamed_product
{% endmacro %}

Et son utilisation:

{% set column_name = 'product' %}
select
 product,
 {{ rename_category(column_name) }} --  
from my_table

DBT est livré avec un gestionnaire de packages qui permet aux utilisateurs de publier et de réutiliser des modules et des macros individuels.

Cela signifie la possibilité de télécharger et d'utiliser des bibliothèques telles que:

  • dbt_utils : travailler avec Date / Heure, ClĂ©s de substitution, Tests de schĂ©ma, Pivot / Unpivot et autres
  • Modèles de vitrine prĂŞts Ă  l'emploi pour des services tels que Snowplow et Stripe 
  • Bibliothèques pour des entrepĂ´ts de donnĂ©es spĂ©cifiques, tels que Redshift 
  • Journalisation - Module de journalisation DBT

Une liste complète des packages est disponible sur dbt hub .

Encore plus de fonctionnalités


Je décrirai ici plusieurs autres fonctionnalités et implémentations intéressantes que moi et l'équipe utilisons pour construire un entrepôt de données à Wheely .

Séparation des environnements d'exécution DEV - TEST - PROD


Même dans le même cluster DWH (dans différents schémas). Par exemple, en utilisant l'expression suivante:

with source as (
 
   select * from {{ source('salesforce', 'users') }}
   where 1=1
   {%- if target.name in ['dev', 'test', 'ci'] -%}           
       where timestamp >= dateadd(day, -3, current_date)   
   {%- endif -%}
 
)

Ce code dit littéralement: pour les environnements dev, test, ci, prenez les données uniquement pour les 3 derniers jours et pas plus. Autrement dit, l'exécution dans ces environnements sera beaucoup plus rapide et nécessitera moins de ressources. Lorsqu'elle est lancée sur un environnement prod , la condition de filtre sera ignorée.

Matérialisation du codage des colonnes alternatives


Redshift est un SGBD de colonne qui vous permet de spécifier des algorithmes de compression de données pour chaque colonne individuelle. Le choix d'algorithmes optimaux peut réduire l'espace disque occupé de 20 à 50%.

La macro redshift.compress_table exécutera la commande ANALYZE COMPRESSION, créera une nouvelle table avec les algorithmes de codage de colonne recommandés indiqués par les clés de segmentation (dist_key) et sort_key (sort_key), leur transférera les données et supprimera l'ancienne copie si nécessaire.

Signature de la macro:

{{ compress_table(schema, table,
                 drop_backup=False,
                 comprows=none|Integer,
                 sort_style=none|compound|interleaved,
                 sort_keys=none|List<String>,
                 dist_style=none|all|even,
                 dist_key=none|String) }}

Lancement du modèle de journalisation


Pour chaque exécution du modèle, vous pouvez accrocher des hooks qui seront exécutés avant le lancement ou immédiatement après la création du modèle:

   pre-hook: "{{ logging.log_model_start_event() }}"
   post-hook: "{{ logging.log_model_end_event() }}"

Le module de journalisation vous permettra d'enregistrer toutes les métadonnées nécessaires dans un tableau séparé, selon lequel vous pourrez ensuite auditer et analyser les zones problématiques (goulots d'étranglement).

Voici à quoi ressemble le tableau de bord sur les données de recherche dans Looker:


Automatisation du stockage


Si vous utilisez des extensions des fonctionnalités du stockage utilisé, telles que UDF (User Defined Functions), la version de ces fonctions, le contrôle d'accès et le déploiement automatique de nouvelles versions sont très pratiques à implémenter dans DBT.

Nous utilisons UDF en Python pour calculer les valeurs de hachage, les domaines de domaine de messagerie et décoder le masque de bits.

Exemple de macro qui crée UDF sur n'importe quel runtime (dev, test, prod):

{% macro create_udf() -%}
 
 {% set sql %}
       CREATE OR REPLACE FUNCTION {{ target.schema }}.f_sha256(mes "varchar")
           RETURNS varchar
           LANGUAGE plpythonu
           STABLE
       AS $$  
           import hashlib
           return hashlib.sha256(mes).hexdigest()
       $$
       ;
 {% endset %}
  
 {% set table = run_query(sql) %}
 
{%- endmacro %}

Chez Wheely, nous utilisons Amazon Redshift, qui est basé sur PostgreSQL. Pour Redshift, il est important de collecter régulièrement des statistiques sur les tables et de libérer de l'espace disque - les commandes ANALYZE et VACUUM, respectivement.

Pour ce faire, les commandes de la macro redshift_maintenance sont exécutées tous les soirs:

{% macro redshift_maintenance() %}
 
   {% set vacuumable_tables=run_query(vacuumable_tables_sql) %}
 
   {% for row in vacuumable_tables %}
       {% set message_prefix=loop.index ~ " of " ~ loop.length %}
 
       {%- set relation_to_vacuum = adapter.get_relation(
                                               database=row['table_database'],
                                               schema=row['table_schema'],
                                               identifier=row['table_name']
                                   ) -%}
       {% do run_query("commit") %}
 
       {% if relation_to_vacuum %}
           {% set start=modules.datetime.datetime.now() %}
           {{ dbt_utils.log_info(message_prefix ~ " Vacuuming " ~ relation_to_vacuum) }}
           {% do run_query("VACUUM " ~ relation_to_vacuum ~ " BOOST") %}
           {{ dbt_utils.log_info(message_prefix ~ " Analyzing " ~ relation_to_vacuum) }}
           {% do run_query("ANALYZE " ~ relation_to_vacuum) %}
           {% set end=modules.datetime.datetime.now() %}
           {% set total_seconds = (end - start).total_seconds() | round(2)  %}
           {{ dbt_utils.log_info(message_prefix ~ " Finished " ~ relation_to_vacuum ~ " in " ~ total_seconds ~ "s") }}
       {% else %}
           {{ dbt_utils.log_info(message_prefix ~ ' Skipping relation "' ~ row.values() | join ('"."') ~ '" as it does not exist') }}
       {% endif %}
 
   {% endfor %}
 
{% endmacro %}

DBT Cloud


Il est possible d'utiliser DBT en tant que service (service géré). Dans un ensemble:

  • IDE Web pour dĂ©velopper des projets et des modèles
  • Configuration du travail et rĂ©glage du calendrier
  • Accès simple et pratique aux journaux
  • Site Web avec la documentation de votre projet
  • Connexion CI (intĂ©gration continue)


Conclusion


Cuisiner et consommer du DWH est tout aussi agréable et bénéfique que boire des smoothies. DBT se compose de Jinja, d'extensions personnalisées (modules), d'un compilateur, d'un moteur (exécuteur) et d'un gestionnaire de packages. Après avoir rassemblé ces éléments, vous obtenez un environnement de travail à part entière pour votre entrepôt de données. Il n'y a guère de meilleure façon de gérer les transformations au sein de DWH aujourd'hui.



Les croyances suivies par les développeurs DBT sont formulées comme suit:

  • Le code, et non l'interface graphique, est la meilleure abstraction pour exprimer une logique analytique complexe
  • Le travail avec les donnĂ©es doit adapter les meilleures pratiques de dĂ©veloppement logiciel (Software Engineering)

  • L'infrastructure de donnĂ©es critique doit ĂŞtre contrĂ´lĂ©e par la communautĂ© des utilisateurs en tant que logiciel open source
  • Non seulement les outils d'analyse, mais le code feront de plus en plus partie de la communautĂ© Open Source.

Ces convictions fondamentales ont donné naissance à un produit qui est utilisé aujourd'hui par plus de 850 entreprises, et elles constituent la base de nombreuses extensions intéressantes qui seront créées à l'avenir.

Pour ceux qui sont intéressés, il y a une vidéo d'une leçon ouverte que j'ai passée il y a quelques mois dans le cadre d'une leçon ouverte sur OTUS - Data Build Tool pour le référentiel Amazon Redshift .

En plus du DBT et des entrepôts de données, dans le cadre du cours Data Engineer sur la plate-forme OTUS, mes collègues et moi-même organisons des cours sur un certain nombre d'autres sujets pertinents et modernes:

  • Concepts architecturaux pour les applications Big Data
  • EntraĂ®nez-vous avec Spark et Spark Streaming
  • MĂ©thodes d'apprentissage et outils de chargement des sources de donnĂ©es
  • CrĂ©ation de vitrines analytiques dans DWH
  • NoSQL: HBase, Cassandra, ElasticSearch
  •  
  • :

:


  1. DBT documentation — Introduction —
  2. What, exactly, is dbt? — DBT 
  3. Data Build Tool Amazon Redshift — YouTube, OTUS
  4. Greenplum — 15 2020
  5. Data Engineering — OTUS
  6. Building a Mature Analytics Workflow —
  7. It’s time for open source analytics — Open Source
  8. Continuous Integration and Automated Build Testing with dbtCloud — CI DBT
  9. Getting started with DBT tutorial — ,
  10. Jaffle shop — Github DBT Tutorial — Github,




.



All Articles