Data Build Tool oder was zwischen einem Data Warehouse und einem Smoothie gemeinsam ist


Was sind die Prinzipien eines idealen Data Warehouse?

Konzentrieren Sie sich auf den Geschäftswert und die Analyse, wenn kein Code für das Boilerplate vorhanden ist. Verwalten von DWH als Codebasis: Versionierung, Überprüfung, automatisierte Tests und CI. Modularität, Erweiterbarkeit, Open Source und Community. Freundliche Benutzerdokumentation und Abhängigkeitsvisualisierung (Data Lineage).

Mehr dazu und zur Rolle von DBT im Big Data & Analytics-Ökosystem - willkommen bei cat.

Hallo alle zusammen


In Kontakt mit Artemy Kozyr. Seit über 5 Jahren arbeite ich mit Data Warehouses, dem Aufbau von ETL / ELT sowie der Datenanalyse und -visualisierung. Ich arbeite derzeit bei Wheely , unterrichte bei OTUS im Data Engineer- Kurs und möchte heute einen Artikel mit Ihnen teilen, den ich am Vorabend des Beginns eines neuen Kurses geschrieben habe .

Kurze Review


Im DBT-Framework dreht sich alles um den Buchstaben T im Akronym ELT (Extract - Transform - Load).

Mit dem Aufkommen produktiver und skalierbarer Analysedatenbanken wie BigQuery, Redshift und Snowflake verschwand jeder Sinn, Transformationen außerhalb des Data Warehouse vorzunehmen. 

DBT lädt keine Daten aus Quellen herunter, bietet jedoch enorme Möglichkeiten, mit Daten zu arbeiten, die bereits in den Speicher geladen wurden (im internen oder externen Speicher).


Der Hauptzweck von DBT besteht darin, den Code zu übernehmen, ihn in SQL zu kompilieren und die Befehle in der richtigen Reihenfolge im Repository auszuführen.

DBT-Projektstruktur


Das Projekt besteht aus Verzeichnissen und Dateien von nur 2 Typen:

  • Modell (.sql) - Transformationseinheit, ausgedrückt durch eine SELECT-Abfrage
  • Konfigurationsdatei (.yml) - Parameter, Einstellungen, Tests, Dokumentation

Grundsätzlich ist die Arbeit wie folgt strukturiert:

  • Der Benutzer bereitet den Modellcode in einer beliebigen IDE vor
  • Über die CLI werden Modelle gestartet, DBT kompiliert den Modellcode in SQL
  • Kompilierter SQL-Code wird im Warehouse in der angegebenen Reihenfolge ausgeführt (Grafik)

So könnte der Start über die CLI aussehen:


Alles ist AUSGEWÄHLT


Dies ist eine Killer-Funktion des Data Build Tool-Frameworks. Mit anderen Worten, DBT abstrahiert den gesamten Code, der sich auf die Materialisierung Ihrer Abfragen im Warehouse bezieht (Abweichungen von den Befehlen CREATE, INSERT, UPDATE, DELETE ALTER, GRANT, ...).

Jedes Modell beinhaltet das Schreiben einer SELECT-Abfrage, die den resultierenden Datensatz definiert.

Gleichzeitig kann die Transformationslogik mehrstufig sein und Daten aus mehreren anderen Modellen konsolidieren. Ein Beispiel für ein Modell, das ein Schaufenster mit Aufträgen erstellt (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

Welche interessanten Dinge können wir hier sehen?

Erstens: CTE (Common Table Expressions) werden verwendet, um Code zu organisieren und zu verstehen, der viele Transformationen und Geschäftslogik enthält

. Zweitens: Modellcode ist eine Mischung aus SQL und der Jinja- Sprache (Template-Sprache).

Im Beispiel wurde die for- Schleife verwendet , um den Betrag für jede im festgelegten Ausdruck angegebene Zahlungsmethode zu bilden . Die ref- Funktion wird ebenfalls verwendet - die Möglichkeit, innerhalb des Codes auf andere Modelle zu verweisen:

  • Zur Kompilierungszeit wird ref in einen Zielzeiger auf eine Tabelle oder Ansicht im Repository konvertiert
  • Mit ref können Sie ein Diagramm der Modellabhängigkeiten erstellen

Es ist Jinja, der DBT nahezu unbegrenzte Möglichkeiten bietet. Die am häufigsten verwendeten:

  • If / else-Anweisungen - Verzweigungsanweisungen
  • Für Schleifen - Schleifen
  • Variablen - Variablen
  • Makro - Makros erstellen

Materialisierung: Tabelle, Ansicht, Inkrementell


Materialisierungsstrategie - Ein Ansatz, nach dem der resultierende Satz von Modelldaten im Repository gespeichert wird.

Grundsätzlich gilt:

  • Tabelle - physische Tabelle im Speicher
  • Ansicht - Ansicht, virtuelle Tabelle im Repository

Es gibt komplexere Materialisierungsstrategien:

  • Inkrementelles - inkrementelles Laden (große Faktentabellen); Neue Zeilen werden hinzugefügt, geänderte aktualisiert, gelöschte gelöscht 
  • Vergänglich - das Modell materialisiert sich nicht direkt, sondern nimmt als CTE an anderen Modellen teil
  • Alle anderen Strategien können Sie selbst hinzufügen

Neben Materialisierungsstrategien eröffnen sich Optimierungsmöglichkeiten für bestimmte Lager, zum Beispiel:

  • Schneeflocke : Transiente Tabellen, Zusammenführungsverhalten, Tabellenclustering, Kopieren von Zuschüssen, Sichere Ansichten
  • Rotverschiebung : Distkey, Sortkey (verschachtelt, zusammengesetzt), Late Binding Views
  • BigQuery : Tabellenpartitionierung und Clustering, Zusammenführungsverhalten, KMS-Verschlüsselung, Beschriftungen und Tags
  • Spark : Dateiformat (Parkett, CSV, JSON, ORC, Delta), partition_by, clustered_by, Buckets, inkrementelle_Strategie

Die folgenden Repositorys werden derzeit unterstützt:

  • Postgres
  • Rotverschiebung
  • Bigquery
  • Schneeflocke
  • Presto (teilweise)
  • Funke (teilweise)
  • Microsoft SQL Server (Community-Adapter)

Lassen Sie uns unser Modell verbessern:

  • Machen Sie die Füllung inkrementell (inkrementell)
  • Fügen Sie Segmentierungs- und Sortierschlüssel für Redshift hinzu

--  : 
--  ,      (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

Modellabhängigkeitsdiagramm


Er ist ein Baum der Abhängigkeiten. Er ist ein DAG (Directed Acyclic Graph - Directional Acyclic Graph).

DBT erstellt ein Diagramm basierend auf der Konfiguration aller Projektmodelle oder ref () verknüpft innerhalb von Modellen mit anderen Modellen. Mit einem Diagramm können Sie Folgendes tun:

  • Modelle in der richtigen Reihenfolge ausführen
  • Parallelisierung der Fensterdekoration
  • Ausführen eines beliebigen Untergraphen 

Beispiel für eine Grafikvisualisierung:


Jeder Knoten des Diagramms ist ein Modell. Die Kanten des Diagramms werden durch den Ausdruck ref angegeben.

Datenqualität und Dokumentation


Zusätzlich zur Bildung der Modelle selbst können Sie mit DBT eine Reihe von Aussagen über den resultierenden Datensatz testen, z.

  • Nicht null
  • Einzigartig
  • Referenzintegrität - Referenzintegrität (z. B. entspricht customer_id in der Auftragstabelle der ID in der Kundentabelle)
  • Übereinstimmende gültige Liste

Sie können Ihre eigenen Tests (benutzerdefinierte Datentests) hinzufügen, z. B. die prozentuale Abweichung des Umsatzes mit Indikatoren vor einem Tag, einer Woche oder einem Monat. Jede als SQL-Abfrage formulierte Annahme kann ein Test sein.

Auf diese Weise können unerwünschte Abweichungen und Fehler in Daten in der Storefront des Speichers abgefangen werden.

In Bezug auf die Dokumentation bietet DBT Mechanismen zum Hinzufügen, Versionsversetzen und Verteilen von Metadaten und Kommentaren auf Modellebene und sogar von Attributen. 

So sieht das Hinzufügen von Tests und Dokumentationen auf Ebene der Konfigurationsdatei aus:

 - 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']

Und so sieht diese Dokumentation bereits auf der generierten Website aus:


Makros und Module


Der Zweck von DBT besteht nicht darin, eine Reihe von SQL-Skripten zu werden, sondern den Benutzern leistungsstarke und funktionsreiche Tools zum Erstellen eigener Transformationen und zum Verteilen dieser Module bereitzustellen.

Makros sind Sätze von Konstrukten und Ausdrücken, die als Funktionen innerhalb von Modellen aufgerufen werden können. Mit Makros können Sie SQL zwischen Modellen und Projekten gemäß dem DRY-Konstruktionsprinzip (Don't Repeat Yourself) wiederverwenden.

Makro Beispiel:

{% 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 %}

Und seine Verwendung:

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

DBT wird mit einem Paketmanager geliefert, mit dem Benutzer einzelne Module und Makros veröffentlichen und wiederverwenden können.

Dies bedeutet die Möglichkeit, Bibliotheken herunterzuladen und zu verwenden, wie z.


Eine vollständige Liste der Pakete finden Sie im dbt Hub .

Noch mehr Funktionen


Hier werde ich einige andere interessante Funktionen und Implementierungen beschreiben, mit denen ich und das Team ein Data Warehouse in Wheely erstellen .

Trennung von Laufzeitumgebungen DEV - TEST - PROD


Auch innerhalb desselben DWH-Clusters (innerhalb verschiedener Schemata). Verwenden Sie beispielsweise den folgenden Ausdruck:

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 -%}
 
)

Dieser Code sagt wörtlich: Nehmen Sie für Entwickler-, Test- und CI- Umgebungen Daten nur für die letzten 3 Tage und nicht mehr. Das heißt, das Ausführen in diesen Umgebungen ist viel schneller und erfordert weniger Ressourcen. Beim Start in einer Produktumgebung wird die Filterbedingung ignoriert.

Alternative Spaltencodierungsmaterialisierung


Redshift ist ein Spalten-DBMS, mit dem Sie Datenkomprimierungsalgorithmen für jede einzelne Spalte angeben können. Durch die Auswahl optimaler Algorithmen kann der belegte Speicherplatz um 20-50% reduziert werden.

Der redshift.compress_table Makro wird der Befehl ANALYZE COMPRESSION ausführen, erstellen Sie eine neue Tabelle mit der empfohlenen Säule Codierungsalgorithmen durch die Segmentierung Tasten (dist_key) angegeben und sort (key_key), die Daten an sie, und löschen Sie die alte Kopie , wenn nötig.

Makrosignatur:

{{ 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) }}

Protokollierungsmodell wird gestartet


Für jede Ausführung des Modells können Sie Hooks aufhängen, die vor dem Start oder unmittelbar nach der Erstellung des Modells ausgeführt werden:

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

Mit dem Protokollierungsmodul können Sie alle erforderlichen Metadaten in einer separaten Tabelle aufzeichnen, anhand derer Sie anschließend Problembereiche (Engpässe) prüfen und analysieren können.

So sieht das Dashboard in den Suchdaten in Looker aus:


Speicherautomatisierung


Wenn Sie einige Erweiterungen der Funktionalität des verwendeten Speichers verwenden, z. B. UDF (User Defined Functions), ist die Versionierung dieser Funktionen, die Zugriffskontrolle und die automatische Einführung neuer Releases in DBT sehr bequem zu implementieren.

Wir verwenden UDF in Python, um Hash-Werte, Mail-Domain-Domänen und Decodierungs-Bitmasken zu berechnen.

Beispielmakro, das UDF zu jeder Laufzeit erstellt (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 %}

Bei Wheely verwenden wir Amazon Redshift, das auf PostgreSQL basiert. Für Redshift ist es wichtig, regelmäßig Statistiken zu Tabellen zu sammeln und Speicherplatz freizugeben - die Befehle ANALYZE und VACUUM.

Dazu werden die Befehle des Makros redshift_maintenance jede Nacht ausgeführt:

{% 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


Es ist möglich, DBT als Service (Managed Service) zu verwenden. Im Komplekt:

  • Web-IDE zur Entwicklung von Projekten und Modellen
  • Jobkonfiguration und Zeitplaneinstellung
  • Einfacher und bequemer Zugriff auf Protokolle
  • Website mit der Dokumentation Ihres Projekts
  • CI-Verbindung (Continuous Integration)


Fazit


Das Kochen und Konsumieren von DWH ist genauso angenehm und vorteilhaft wie das Trinken von Smoothies. DBT besteht aus Jinja, benutzerdefinierten Erweiterungen (Modulen), Compiler, Engine (Executor) und Paketmanager. Nachdem Sie diese Elemente zusammengetragen haben, erhalten Sie eine vollwertige Arbeitsumgebung für Ihr Data Warehouse. Es gibt heute kaum einen besseren Weg, um Transformationen innerhalb von DWH zu verwalten.



Die Überzeugungen der DBT-Entwickler lauten wie folgt:

  • Code, nicht GUI, ist die beste Abstraktion, um komplexe analytische Logik auszudrücken
  • Die Arbeit mit Daten sollte die Best Practices der Softwareentwicklung (Software Engineering) anpassen.

  • Kritische Dateninfrastruktur muss von der Benutzergemeinschaft als Open-Source-Software gesteuert werden
  • Nicht nur Analysetools, sondern auch Code werden zunehmend Teil der Open Source-Community.

Diese Grundüberzeugungen haben ein Produkt hervorgebracht, das heute von mehr als 850 Unternehmen verwendet wird, und sie bilden die Grundlage für viele interessante Erweiterungen, die in Zukunft erstellt werden.

Für Interessierte gibt es ein Video einer offenen Lektion, die ich vor einigen Monaten im Rahmen einer offenen Lektion im OTUS - Data Build Tool für Amazon Redshift-Repository verbracht habe .

Neben DBT und Data Warehouses führen meine Kollegen und ich im Rahmen des Data Engineer-Kurses auf der OTUS-Plattform Kurse zu einer Reihe anderer relevanter und moderner Themen durch:

  • Architekturkonzepte für Big Data-Anwendungen
  • Übe mit Spark und Spark Streaming
  • Lernmethoden und Tools zum Laden von Datenquellen
  • Erstellen von analytischen Vitrinen in 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