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 logiquemé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
{{
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
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
-
- :
:
- DBT documentation — Introduction —
- What, exactly, is dbt? — DBT
- Data Build Tool Amazon Redshift — YouTube, OTUS
- Greenplum — 15 2020
- Data Engineering — OTUS
- Building a Mature Analytics Workflow —
- It’s time for open source analytics — Open Source
- Continuous Integration and Automated Build Testing with dbtCloud — CI DBT
- Getting started with DBT tutorial — ,
- Jaffle shop — Github DBT Tutorial — Github,
.