- Création d’un projet dbt et configuration de l’adaptateur ClickHouse.
- Définition d’un modèle.
- Mise à jour d’un modèle.
- Création d’un modèle incrémentiel.
- Création d’un modèle snapshot.
- Utilisation de vues matérialisées.
Configuration
Préparer ClickHouse
La colonne
created_at de la table roles a pour valeur par défaut now(). Nous l’utilisons plus tard pour identifier les mises à jour incrémentales de nos modèles ; voir Modèles incrémentaux.s3 pour lire les données source depuis des endpoints publics afin d’insérer les données. Exécutez les commandes suivantes pour remplir les tables :
Connexion à ClickHouse
-
Créez un projet dbt. Dans ce cas, nous le nommons d’après notre source
imdb. Lorsque vous y êtes invité, sélectionnezclickhousecomme base de données source. -
Placez-vous dans le dossier de votre projet avec
cd: - À ce stade, vous aurez besoin de l’éditeur de texte de votre choix. Dans les exemples ci-dessous, nous utilisons le très répandu VS Code. En ouvrant le répertoire IMDB, vous devriez voir un ensemble de fichiers yml et sql :
-
Mettez à jour votre fichier
dbt_project.ymlpour spécifier notre premier modèle,actor_summary, et définir le profil surclickhouse_imdb. -
Nous devons ensuite fournir à dbt les informations de connexion de notre instance ClickHouse. Ajoutez le contenu suivant à votre fichier
~/.dbt/profiles.yml.Notez qu’il faut modifier l’utilisateur et le mot de passe. D’autres paramètres disponibles sont documentés ici. -
Depuis le répertoire IMDB, exécutez la commande
dbt debugpour vérifier que dbt peut se connecter à ClickHouse.Vérifiez que la réponse inclutConnection test: [OK connection ok], ce qui indique que la connexion a réussi.
Création d’une matérialisation de vue simple
CREATE VIEW AS dans ClickHouse. Cela ne nécessite aucun stockage de données supplémentaire, mais les requêtes seront plus lentes qu’avec des matérialisations en table.
-
Dans le dossier
imdb, supprimez le répertoiremodels/example: -
Créez un nouveau fichier dans
actors, au sein du dossiermodels. C’est ici que nous créons les fichiers, chacun représentant un modèle d’acteur : -
Créez les fichiers
schema.ymletactor_summary.sqldans le dossiermodels/actors.Le fichierschema.ymldéfinit nos tables. Elles pourront ensuite être utilisées dans les macros. Modifiezmodels/actors/schema.ymlpour qu’il contienne le contenu suivant :Le fichieractors_summary.sqldéfinit notre modèle proprement dit. Notez que, dans la fonctionconfig, nous demandons également que le modèle soit matérialisé en vue dans ClickHouse. Nos tables sont référencées depuis le fichierschema.ymlvia la fonctionsource; par exemple,source('imdb', 'movies')fait référence à la tablemoviesdans la base de donnéesimdb. Modifiezmodels/actors/actors_summary.sqlpour y mettre le contenu suivant :Remarquez que nous incluons la colonneupdated_atdans notre actor_summary final. Nous l’utilisons ensuite pour les matérialisations incrémentielles. -
Dans le répertoire
imdb, exécutez la commandedbt run. -
dbt représentera le modèle sous forme de vue dans ClickHouse, comme demandé. Nous pouvons maintenant interroger cette vue directement. Cette vue aura été créée dans la base de données
imdb_dbt— cela est déterminé par le paramètre schema dans le fichier~/.dbt/profiles.yml, sous le profilclickhouse_imdb.En interrogeant cette vue, nous pouvons reproduire les résultats de notre requête précédente avec une syntaxe plus simple :
Création d’une matérialisation en table
INSERT TO SELECT est effectivement exécuté. Notez que cette table sera reconstruite à chaque exécution, c.-à-d. qu’elle n’est pas incrémentielle. De grands ensembles de résultats peuvent donc entraîner des temps d’exécution élevés — voir Limitations de dbt.
-
Modifiez le fichier
actors_summary.sqlafin que le paramètrematerializedsoit défini surtable. Notez commentORDER BYest défini, ainsi que l’utilisation du moteur de tableMergeTree: -
Depuis le répertoire
imdb, exécutez la commandedbt run. Cette exécution peut prendre un peu plus de temps — environ 10 s sur la plupart des machines. -
Confirmez la création de la table
imdb_dbt.actor_summary:Vous devriez voir la table avec les types de données appropriés : -
Confirmez que les résultats de cette table sont cohérents avec les réponses précédentes. Notez l’amélioration sensible du temps de réponse maintenant que le modèle est une table :
N’hésitez pas à exécuter d’autres requêtes sur ce modèle. Par exemple, quels acteurs ont les films les mieux classés avec plus de 5 apparitions ?
Création d’une matérialisation incrémentielle
-
D’abord, nous modifions notre modèle pour qu’il soit de type incrémental. Cet ajout nécessite :
- unique_key - Pour garantir que l’adaptateur puisse identifier les lignes de manière unique, nous devons fournir une unique_key - dans ce cas, le champ
idde notre requête suffit. Cela garantit l’absence de doublons de lignes dans notre table matérialisée. Pour plus de détails sur les contraintes d’unicité, voir ici. - Filtre incrémental - Nous devons également indiquer à dbt comment identifier les lignes qui ont changé lors d’une exécution incrémentale. Pour cela, il faut fournir une expression delta. En général, cela implique un timestamp pour les données d’événements, d’où notre champ timestamp updated_at. Cette colonne, dont la valeur par défaut est
now()lorsque des lignes sont insérées, permet d’identifier les nouveaux rôles. De plus, nous devons prendre en compte l’autre cas possible, où de nouveaux acteurs sont ajoutés. En utilisant la variable{{this}}pour désigner la table matérialisée existante, on obtient l’expressionwhere id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}}). Nous l’intégrons dans la condition{% if is_incremental() %}, ce qui garantit qu’elle n’est utilisée que lors des exécutions incrémentales, et non lors de la création initiale de la table. Pour plus de détails sur le filtrage des lignes pour les modèles incrémentaux, voir cette section de la documentation dbt.
actor_summary.sqlcomme suit :Notez que notre modèle ne réagira qu’aux mises à jour et aux ajouts apportés aux tablesrolesetactors. Pour prendre en compte toutes les tables, il est recommandé aux utilisateurs de scinder ce modèle en plusieurs sous-modèles, chacun avec ses propres critères incrémentiels. Ces modèles pourront ensuite être référencés et reliés entre eux. Pour plus de détails sur les références croisées entre modèles, consultez ici. - unique_key - Pour garantir que l’adaptateur puisse identifier les lignes de manière unique, nous devons fournir une unique_key - dans ce cas, le champ
-
Exécutez un
dbt runet vérifiez les résultats de la table obtenue : -
Nous allons maintenant ajouter des données à notre modèle pour illustrer une mise à jour incrémentielle. Ajoutez l’acteur “Clicky McClickHouse” à la table
actors: -
Faisons jouer « Clicky » dans 910 films choisis au hasard :
-
Confirmez qu’il s’agit bien désormais de l’acteur comptant le plus d’apparitions en interrogeant la table source sous-jacente et en contournant tous les modèles dbt :
-
Lancez un
dbt runet vérifiez que notre modèle a bien été mis à jour et qu’il correspond aux résultats ci-dessus :
Fonctionnement interne
- L’adaptateur crée une table temporaire
actor_sumary__dbt_tmp. Les lignes modifiées y sont envoyées. - Une nouvelle table,
actor_summary_new,est créée. Les lignes de l’ancienne table sont ensuite envoyées de l’ancienne vers la nouvelle, en vérifiant que leurs identifiants n’existent pas dans la table temporaire. Cela permet de gérer efficacement les mises à jour et les doublons. - Les résultats de la table temporaire sont envoyés vers la nouvelle table
actor_summary: - Enfin, la nouvelle table est échangée de manière atomique avec l’ancienne version via une instruction
EXCHANGE TABLES. L’ancienne table et la table temporaire sont ensuite supprimées.
Stratégie append (mode insertions uniquement)
incremental_strategy. Il peut être défini sur la valeur append. Dans ce cas, les lignes mises à jour sont insérées directement dans la table cible (autrement dit imdb_dbt.actor_summary) et aucune table temporaire n’est créée.
Remarque : le mode append uniquement nécessite que vos données soient immuables ou que les doublons soient acceptables. Si vous voulez un modèle de table incrémentielle qui prend en charge les lignes modifiées, n’utilisez pas ce mode !
Pour illustrer ce mode, nous allons ajouter un nouvel acteur et réexécuter dbt run avec incremental_strategy='append'.
-
Configurez le mode append uniquement dans actor_summary.sql :
-
Ajoutons un autre acteur célèbre : Danny DeBito
-
Faisons jouer Danny dans 920 films pris au hasard.
-
Exécutez
dbt runet confirmez que Danny a bien été ajouté à la table actor_summary
imdb_dbt.actor_summary, sans création de table.
Mode suppression et insertion (expérimental)
incremental_strategy, c.-à-d.
- L’adaptateur crée une table temporaire
actor_sumary__dbt_tmp. Les lignes modifiées y sont envoyées. - Un
DELETEest exécuté sur la tableactor_summaryactuelle. Les lignes sont supprimées par id à partir deactor_sumary__dbt_tmp - Les lignes de
actor_sumary__dbt_tmpsont insérées dansactor_summaryà l’aide deINSERT INTO actor_summary SELECT * FROM actor_sumary__dbt_tmp.
Mode insert_overwrite (expérimental)
- Crée une table de staging (temporaire) ayant la même structure que la relation du modèle incrémental :
CREATE TABLE {staging} AS {target}. - Insère uniquement les nouveaux enregistrements (produits par SELECT) dans la table de staging.
- Remplace uniquement les nouvelles partitions (présentes dans la table de staging) dans la table cible.
Cette approche présente les avantages suivants :
- Elle est plus rapide que la stratégie par défaut, car elle ne copie pas l’intégralité de la table.
- Elle est plus sûre que les autres stratégies, car elle ne modifie pas la table d’origine tant que l’opération INSERT n’a pas abouti : en cas d’échec intermédiaire, la table d’origine n’est pas modifiée.
- Elle applique la bonne pratique d’ingénierie des données dite de « l’immuabilité des partitions », ce qui simplifie le traitement incrémental et parallèle des données, les retours arrière, etc.
Créer un snapshot
-
Créez un fichier
actor_summarydans le répertoire snapshots. -
Mettez à jour le contenu du fichier actor_summary.sql avec le contenu suivant :
- La requête select définit les résultats dont vous souhaitez capturer un snapshot au fil du temps. La fonction ref est utilisée pour faire référence à notre modèle actor_summary créé précédemment.
- Nous avons besoin d’une colonne timestamp pour indiquer les modifications des enregistrements. Notre colonne updated_at (voir Création d’un modèle de table Incremental) peut être utilisée ici. Le paramètre strategy indique que nous utilisons un timestamp pour signaler les mises à jour, tandis que le paramètre updated_at précise la colonne à utiliser. Si ce champ n’est pas présent dans votre modèle, vous pouvez également utiliser la stratégie check. Cette approche est nettement moins efficace et oblige l’utilisateur à spécifier une liste de colonnes à comparer. dbt compare les valeurs actuelles et historiques de ces colonnes, en enregistrant toute modification (ou en ne faisant rien si elles sont identiques).
-
Exécutez la commande
dbt snapshot.
-
Si vous examinez un échantillon de ces données, vous verrez que dbt a inclus les colonnes dbt_valid_from et dbt_valid_to. Cette dernière contient des valeurs null. Les exécutions suivantes le mettront à jour.
-
Faites apparaître notre acteur préféré, Clicky McClickHouse, dans 10 films supplémentaires.
-
Relancez la commande
dbt rundepuis le répertoireimdb. Cela mettra à jour le modèle incrémental. Une fois l’opération terminée, exécutezdbt snapshotpour capturer les modifications. -
Si nous interrogeons maintenant notre instantané, nous constatons que nous avons 2 lignes pour Clicky McClickHouse. Notre entrée précédente a désormais une valeur dbt_valid_to. Notre nouvelle valeur est enregistrée avec la même valeur dans la colonne dbt_valid_from, et une valeur dbt_valid_to égale à null. Si nous avions de nouvelles lignes, elles seraient également ajoutées à l’instantané.
Utiliser les seeds
-
Nous générons une liste de codes de genre à partir de notre jeu de données existant. Depuis le répertoire dbt, utilisez
clickhouse-clientpour créer un fichierseeds/genre_codes.csv: -
Exécutez la commande
dbt seed. Cela créera une nouvelle tablegenre_codesdans notre base de donnéesimdb_dbt(comme défini par notre configuration de schéma) avec les lignes de notre fichier CSV. -
Vérifiez qu’elles ont bien été chargées :