Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Guías

Compatible con ClickHouse

Esta sección proporciona guías para configurar dbt y el adaptador de ClickHouse, así como un ejemplo de uso de dbt con ClickHouse a partir de un conjunto de datos público de IMDB. El ejemplo abarca los siguientes pasos:

  1. Crear un proyecto de dbt y configurar el adaptador de ClickHouse.
  2. Definir un modelo.
  3. Actualizar un modelo.
  4. Crear un modelo incremental.
  5. Crear un modelo snapshot.
  6. Usar vistas materializadas.

Estas guías están pensadas para usarse junto con el resto de la documentación, las características y configuraciones y la referencia de materializaciones.

Configuración

Sigue las instrucciones de la sección Configuración de dbt y el adaptador de ClickHouse para preparar tu entorno.

Importante: Lo siguiente se ha probado con Python 3.9.

Preparar ClickHouse

dbt destaca al modelar datos con muchas relaciones. A modo de ejemplo, proporcionamos un pequeño conjunto de datos de IMDb con el siguiente esquema relacional. Este conjunto de datos proviene del repositorio de conjuntos de datos relacionales. Aunque es sencillo en comparación con los esquemas habituales que se usan con dbt, representa una muestra manejable:

Esquema de tablas de IMDb

Usamos un subconjunto de estas tablas, como se muestra.

Cree las siguientes tablas:

CREATE DATABASE imdb;

CREATE TABLE imdb.actors
(
    id         UInt32,
    first_name String,
    last_name  String,
    gender     FixedString(1)
) ENGINE = MergeTree ORDER BY (id, first_name, last_name, gender);

CREATE TABLE imdb.directors
(
    id         UInt32,
    first_name String,
    last_name  String
) ENGINE = MergeTree ORDER BY (id, first_name, last_name);

CREATE TABLE imdb.genres
(
    movie_id UInt32,
    genre    String
) ENGINE = MergeTree ORDER BY (movie_id, genre);

CREATE TABLE imdb.movie_directors
(
    director_id UInt32,
    movie_id    UInt64
) ENGINE = MergeTree ORDER BY (director_id, movie_id);

CREATE TABLE imdb.movies
(
    id   UInt32,
    name String,
    year UInt32,
    rank Float32 DEFAULT 0
) ENGINE = MergeTree ORDER BY (id, name, year);

CREATE TABLE imdb.roles
(
    actor_id   UInt32,
    movie_id   UInt32,
    role       String,
    created_at DateTime DEFAULT now()
) ENGINE = MergeTree ORDER BY (actor_id, movie_id);

Usamos la función s3 para leer los datos de origen desde endpoints públicos e insertarlos. Ejecuta los siguientes comandos para rellenar las tablas:

INSERT INTO imdb.actors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_actors.tsv.gz', NOSIGN,
'TSVWithNames');

INSERT INTO imdb.directors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_directors.tsv.gz', NOSIGN,
'TSVWithNames');

INSERT INTO imdb.genres
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies_genres.tsv.gz', NOSIGN,
'TSVWithNames');

INSERT INTO imdb.movie_directors
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies_directors.tsv.gz', NOSIGN,
        'TSVWithNames');

INSERT INTO imdb.movies
SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_movies.tsv.gz', NOSIGN,
'TSVWithNames');

INSERT INTO imdb.roles(actor_id, movie_id, role)
SELECT actor_id, movie_id, role
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/imdb/imdb_ijs_roles.tsv.gz', NOSIGN,
'TSVWithNames');

La ejecución de estos pasos puede variar en función de tu ancho de banda, pero cada uno debería tardar solo unos segundos en completarse. Ejecuta la siguiente consulta para obtener un resumen de cada actor, ordenado por número de apariciones en películas de mayor a menor, y confirmar que los datos se hayan cargado correctamente:

SELECT id,
       any(actor_name)          AS name,
       uniqExact(movie_id)    AS num_movies,
       avg(rank)                AS avg_rank,
       uniqExact(genre)         AS unique_genres,
       uniqExact(director_name) AS uniq_directors,
       max(created_at)          AS updated_at
FROM (
         SELECT imdb.actors.id  AS id,
                concat(imdb.actors.first_name, ' ', imdb.actors.last_name)  AS actor_name,
                imdb.movies.id AS movie_id,
                imdb.movies.rank AS rank,
                genre,
                concat(imdb.directors.first_name, ' ', imdb.directors.last_name) AS director_name,
                created_at
         FROM imdb.actors
                  JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id
                  LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id
                  LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id
                  LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id
                  LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id
         )
GROUP BY id
ORDER BY num_movies DESC
LIMIT 5;

La respuesta debería verse así:

+------+------------+----------+------------------+-------------+--------------+-------------------+
|id    |name        |num_movies|avg_rank          |unique_genres|uniq_directors|updated_at         |
+------+------------+----------+------------------+-------------+--------------+-------------------+
|45332 |Mel Blanc   |832       |6.175853582979779 |18           |84            |2022-04-26 14:01:45|
|621468|Bess Flowers|659       |5.57727638854796  |19           |293           |2022-04-26 14:01:46|
|372839|Lee Phelps  |527       |5.032976449684617 |18           |261           |2022-04-26 14:01:46|
|283127|Tom London  |525       |2.8721716524875673|17           |203           |2022-04-26 14:01:46|
|356804|Bud Osborne |515       |2.0389507108727773|15           |149           |2022-04-26 14:01:46|
+------+------------+----------+------------------+-------------+--------------+-------------------+

En las guías siguientes, convertiremos esta consulta en un modelo, materializándolo en ClickHouse como una vista y una tabla de dbt.

Conexión a ClickHouse

  1. Cree un proyecto de dbt. En este caso, le damos el nombre de nuestra source imdb. Cuando se le solicite, seleccione clickhouse como origen de la base de datos.

    clickhouse-user@clickhouse:~$ dbt init imdb
    
    16:52:40  Running with dbt=1.1.0
    Which database would you like to use?
    [1] clickhouse
    
    (Don't see the one you want? https://docs.getdbt.com/docs/available-adapters)
    
    Enter a number: 1
    16:53:21  No sample profile found for clickhouse.
    16:53:21
    Your new dbt project "imdb" was created!
    
    For more information on how to configure the profiles.yml file,
    please consult the dbt documentation here:
    
    https://docs.getdbt.com/docs/configure-your-profile
  2. Entre en la carpeta de su proyecto con cd:

    cd imdb
  3. En este punto, necesitará el editor de texto que prefiera. En los ejemplos siguientes, usamos el popular VS Code. Al abrir el directorio IMDB, debería ver un conjunto de archivos yml y sql:

    Nuevo proyecto de dbt
  4. Actualice su archivo dbt_project.yml para especificar nuestro primer modelo, actor_summary, y establezca el profile en clickhouse_imdb.

    profile de dbt
    profile de dbt
  5. A continuación, debemos proporcionar a dbt los connection details de nuestra instancia de ClickHouse. Añada lo siguiente a ~/.dbt/profiles.yml:

    clickhouse_imdb:
      target: dev
      outputs:
        dev:
          type: clickhouse
          schema: imdb_dbt
          host: localhost
          port: 8123
          user: default
          password: ''
          secure: False

    Tenga en cuenta que debe modificar el usuario y la contraseña. Hay más opciones de configuración documentadas aquí.

  6. Desde el directorio IMDB, ejecute el comando dbt debug para confirmar si dbt puede conectarse a ClickHouse.

    clickhouse-user@clickhouse:~/imdb$ dbt debug
    17:33:53  Running with dbt=1.1.0
    dbt version: 1.1.0
    python version: 3.10.1
    python path: /home/dale/.pyenv/versions/3.10.1/bin/python3.10
    os info: Linux-5.13.0-10039-tuxedo-x86_64-with-glibc2.31
    Using profiles.yml file at /home/dale/.dbt/profiles.yml
    Using dbt_project.yml file at /opt/dbt/imdb/dbt_project.yml
    
    Configuration:
    profiles.yml file [OK found and valid]
    dbt_project.yml file [OK found and valid]
    
    Required dependencies:
    - git [OK found]
    
    Connection:
    host: localhost
    port: 8123
    user: default
    schema: imdb_dbt
    secure: False
    verify: False
    Connection test: [OK connection ok]
    
    All checks passed!

    Confirme que la respuesta incluya Connection test: [OK connection ok], lo que indica que la conexión se ha realizado correctamente.

Crear una materialización de vista simple

Cuando se usa la materialización de vista, un modelo se vuelve a crear como una vista en cada ejecución mediante una instrucción CREATE VIEW AS en ClickHouse. Esto no requiere almacenamiento adicional de datos, pero las consultas serán más lentas que con las materializaciones de tabla.

  1. En la carpeta imdb, elimine el directorio models/example:

    clickhouse-user@clickhouse:~/imdb$ rm -rf models/example
  2. Cree un archivo nuevo en actors dentro de la carpeta models. Aquí creamos archivos, cada uno de los cuales representa un modelo de actores:

    clickhouse-user@clickhouse:~/imdb$ mkdir models/actors
  3. Crea los archivos schema.yml y actor_summary.sql en la carpeta models/actors.

    clickhouse-user@clickhouse:~/imdb$ touch models/actors/actor_summary.sql
    clickhouse-user@clickhouse:~/imdb$ touch models/actors/schema.yml

    El archivo schema.yml define nuestras tablas. Posteriormente, estas estarán disponibles para usarse en macros. Edit models/actors/schema.yml para que contenga lo siguiente:

    version: 2
    
    sources:
    - name: imdb
      tables:
      - name: directors
      - name: actors
      - name: roles
      - name: movies
      - name: genres
      - name: movie_directors

    actors_summary.sql define nuestro modelo propiamente dicho. Tenga en cuenta que, en la función config, también indicamos que el modelo se materialice como una vista en ClickHouse. Nuestras tablas se referencian desde el archivo schema.yml mediante la función source; por ejemplo, source('imdb', 'movies') se refiere a la tabla movies de la base de datos imdb. Edite models/actors/actors_summary.sql para que contenga lo siguiente:

    {{ config(materialized='view') }}
    
    with actor_summary as (
    SELECT id,
        any(actor_name) as name,
        uniqExact(movie_id)    as num_movies,
        avg(rank)                as avg_rank,
        uniqExact(genre)         as genres,
        uniqExact(director_name) as directors,
        max(created_at) as updated_at
    FROM (
            SELECT {{ source('imdb', 'actors') }}.id as id,
                    concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name,
                    {{ source('imdb', 'movies') }}.id as movie_id,
                    {{ source('imdb', 'movies') }}.rank as rank,
                    genre,
                    concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name,
                    created_at
            FROM {{ source('imdb', 'actors') }}
                        JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id
                        LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id
                        LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id
                        LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id
                        LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id
            )
    GROUP BY id
    )
    
    select *
    from actor_summary

    Fíjate en cómo incluimos la columna updated_at en nuestro actor_summary final. Más adelante la usamos para las materializaciones incrementales.

  4. Desde el directorio imdb, ejecuta el comando dbt run.

    clickhouse-user@clickhouse:~/imdb$ dbt run
    15:05:35  Running with dbt=1.1.0
    15:05:35  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics
    15:05:35
    15:05:36  Concurrency: 1 threads (target='dev')
    15:05:36
    15:05:36  1 of 1 START view model imdb_dbt.actor_summary.................................. [RUN]
    15:05:37  1 of 1 OK created view model imdb_dbt.actor_summary............................. [OK in 1.00s]
    15:05:37
    15:05:37  Finished running 1 view model in 1.97s.
    15:05:37
    15:05:37  Completed successfully
    15:05:37
    15:05:37  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
  5. dbt representará el model como una vista en ClickHouse, tal como se solicitó. Ahora podemos consultar esta vista directamente. Esta vista se habrá creado en la base de datos imdb_dbt; esto lo determina el parámetro schema en el archivo ~/.dbt/profiles.yml, dentro del profile clickhouse_imdb.

    SHOW DATABASES;
    +------------------+
    |name              |
    +------------------+
    |INFORMATION_SCHEMA|
    |default           |
    |imdb              |
    |imdb_dbt          |  <---creado por dbt!
    |information_schema|
    |system            |
    +------------------+

    Al consultar esta vista, podemos reproducir los resultados de nuestra consulta anterior con una sintaxis más sencilla:

    SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
    +------+------------+----------+------------------+------+---------+-------------------+
    |id    |name        |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+------------+----------+------------------+------+---------+-------------------+
    |45332 |Mel Blanc   |832       |6.175853582979779 |18    |84       |2022-04-26 15:26:55|
    |621468|Bess Flowers|659       |5.57727638854796  |19    |293      |2022-04-26 15:26:57|
    |372839|Lee Phelps  |527       |5.032976449684617 |18    |261      |2022-04-26 15:26:56|
    |283127|Tom London  |525       |2.8721716524875673|17    |203      |2022-04-26 15:26:56|
    |356804|Bud Osborne |515       |2.0389507108727773|15    |149      |2022-04-26 15:26:56|
    +------+------------+----------+------------------+------+---------+-------------------+

Crear una materialización como tabla

En el ejemplo anterior, nuestro modelo se materializó como una vista. Aunque esto puede ofrecer un rendimiento suficiente para algunas consultas, los SELECT más complejos o las consultas que se ejecutan con frecuencia pueden materializarse mejor como una tabla. Esta materialización resulta útil para los modelos que serán consultados por herramientas de BI, ya que garantiza una experiencia más ágil para los usuarios. En la práctica, esto hace que los resultados de la consulta se almacenen en una nueva tabla, con la sobrecarga de almacenamiento asociada; en efecto, se ejecuta un INSERT TO SELECT. Ten en cuenta que esta tabla se reconstruirá cada vez; es decir, no es incremental. Por lo tanto, los conjuntos de resultados grandes pueden dar lugar a tiempos de ejecución prolongados; consulta dbt Limitations.

  1. Modifica el archivo actors_summary.sql para que el parámetro materialized se establezca en table. Observa cómo se define ORDER BY y que usamos el motor de tabla MergeTree:

    {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='table') }}
  2. Desde el directorio imdb, ejecuta el comando dbt run. Esta ejecución puede tardar un poco más en completarse: alrededor de 10 s en la mayoría de los equipos.

    clickhouse-user@clickhouse:~/imdb$ dbt run
    15:13:27  Running with dbt=1.1.0
    15:13:27  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics
    15:13:27
    15:13:28  Concurrency: 1 threads (target='dev')
    15:13:28
    15:13:28  1 of 1 START table model imdb_dbt.actor_summary................................. [RUN]
    15:13:37  1 of 1 OK created table model imdb_dbt.actor_summary............................ [OK in 9.22s]
    15:13:37
    15:13:37  Finished running 1 table model in 10.20s.
    15:13:37
    15:13:37  Completed successfully
    15:13:37
    15:13:37  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
  3. Confirma la creación de la tabla imdb_dbt.actor_summary:

    SHOW CREATE TABLE imdb_dbt.actor_summary;

    Deberías ver la tabla con los tipos de datos adecuados:

    +----------------------------------------
    |statement
    +----------------------------------------
    |CREATE TABLE imdb_dbt.actor_summary
    |(
    |`id` UInt32,
    |`first_name` String,
    |`last_name` String,
    |`num_movies` UInt64,
    |`updated_at` DateTime
    |)
    |ENGINE = MergeTree
    |ORDER BY (id, first_name, last_name)
    +----------------------------------------
  4. Confirma que los resultados de esta tabla sean coherentes con las respuestas anteriores. Observa una mejora apreciable en el tiempo de respuesta ahora que el modelo es una tabla:

    SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
    +------+------------+----------+------------------+------+---------+-------------------+
    |id    |name        |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+------------+----------+------------------+------+---------+-------------------+
    |45332 |Mel Blanc   |832       |6.175853582979779 |18    |84       |2022-04-26 15:26:55|
    |621468|Bess Flowers|659       |5.57727638854796  |19    |293      |2022-04-26 15:26:57|
    |372839|Lee Phelps  |527       |5.032976449684617 |18    |261      |2022-04-26 15:26:56|
    |283127|Tom London  |525       |2.8721716524875673|17    |203      |2022-04-26 15:26:56|
    |356804|Bud Osborne |515       |2.0389507108727773|15    |149      |2022-04-26 15:26:56|
    +------+------------+----------+------------------+------+---------+-------------------+

    No dudes en ejecutar otras consultas sobre este modelo. Por ejemplo, ¿qué actores tienen las películas mejor valoradas con más de 5 apariciones?

    SELECT * FROM imdb_dbt.actor_summary WHERE num_movies > 5 ORDER BY avg_rank  DESC LIMIT 10;

Creación de una materialización incremental

El ejemplo anterior creó una tabla para materializar el modelo. Esta tabla se reconstruirá en cada ejecución de dbt. Esto puede resultar inviable y extremadamente costoso para conjuntos de resultados grandes o transformaciones complejas. Para abordar este problema y reducir el tiempo de construcción, dbt ofrece materializaciones incrementales. Esto permite a dbt insertar o actualizar registros en una tabla desde la última ejecución, por lo que resulta adecuado para datos de tipo evento. Internamente, se crea una tabla temporal con todos los registros actualizados y, a continuación, tanto los registros no modificados como los actualizados se insertan en una nueva tabla de destino. Esto conlleva limitaciones similares para conjuntos de resultados grandes a las del modelo de tabla.

Para superar estas limitaciones en conjuntos grandes, el adaptador admite el modo 'inserts_only', en el que todas las actualizaciones se insertan en la tabla de destino sin crear una tabla temporal (más información a continuación).

Para ilustrar este ejemplo, añadiremos al actor "Clicky McClickHouse", que aparecerá en la friolera de 910 películas, lo que garantiza que haya aparecido en más filmes incluso que Mel Blanc.

  1. Primero, modificamos nuestro modelo para que sea incremental. Este cambio requiere:

    1. unique_key - Para garantizar que el adaptador pueda identificar de forma unívoca las filas, debemos proporcionar una unique_key; en este caso, el campo id de nuestra consulta será suficiente. Esto garantiza que no tendremos filas duplicadas en nuestra tabla materializada. Para obtener más información sobre las restricciones de unicidad, consulta aquí.
    2. Filtro incremental - También debemos indicarle a dbt cómo identificar qué filas han cambiado en una ejecución incremental. Esto se consigue proporcionando una expresión delta. Normalmente, esto implica un timestamp para los datos de eventos; de ahí nuestro campo de timestamp updated_at. Esta columna, cuyo valor predeterminado es now() cuando se insertan filas, permite identificar nuevos roles. Además, necesitamos contemplar el caso alternativo en el que se agregan nuevos actores. Usando la variable {{this}} para denotar la tabla materializada existente, obtenemos la expresión where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}}). La incrustamos dentro de la condición {% if is_incremental() %}, lo que garantiza que solo se use en ejecuciones incrementales y no cuando la tabla se construye por primera vez. Para obtener más información sobre cómo filtrar filas en modelos incrementales, consulta este apartado de la documentación de dbt.

    Actualiza el archivo actor_summary.sql de la siguiente manera:

    {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id') }}
    with actor_summary as (
        SELECT id,
            any(actor_name) as name,
            uniqExact(movie_id)    as num_movies,
            avg(rank)                as avg_rank,
            uniqExact(genre)         as genres,
            uniqExact(director_name) as directors,
            max(created_at) as updated_at
        FROM (
            SELECT {{ source('imdb', 'actors') }}.id as id,
                concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name,
                {{ source('imdb', 'movies') }}.id as movie_id,
                {{ source('imdb', 'movies') }}.rank as rank,
                genre,
                concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name,
                created_at
        FROM {{ source('imdb', 'actors') }}
            JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id
            LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id
            LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id
            LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id
            LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id
        )
        GROUP BY id
    )
    select *
    from actor_summary
    
    {% if is_incremental() %}
    
    -- este filtro solo se aplicará en una ejecución incremental
    where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})
    
    {% endif %}

    Ten en cuenta que nuestro modelo solo responderá a las actualizaciones y adiciones en las tablas roles y actors. Para responder a todas las tablas, se recomienda a los usuarios dividir este modelo en varios submodelos, cada uno con sus propios criterios incrementales. A su vez, estos modelos pueden referenciarse y conectarse entre sí. Para obtener más información sobre las referencias cruzadas entre modelos, consulta aquí.

  2. Ejecuta dbt run y confirma los resultados de la tabla generada:

    clickhouse-user@clickhouse:~/imdb$  dbt run
    15:33:34  Running with dbt=1.1.0
    15:33:34  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics
    15:33:34
    15:33:35  Concurrency: 1 threads (target='dev')
    15:33:35
    15:33:35  1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN]
    15:33:41  1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 6.33s]
    15:33:41
    15:33:41  Finished running 1 incremental model in 7.30s.
    15:33:41
    15:33:41  Completed successfully
    15:33:41
    15:33:41  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
    SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 5;
    +------+------------+----------+------------------+------+---------+-------------------+
    |id    |name        |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+------------+----------+------------------+------+---------+-------------------+
    |45332 |Mel Blanc   |832       |6.175853582979779 |18    |84       |2022-04-26 15:26:55|
    |621468|Bess Flowers|659       |5.57727638854796  |19    |293      |2022-04-26 15:26:57|
    |372839|Lee Phelps  |527       |5.032976449684617 |18    |261      |2022-04-26 15:26:56|
    |283127|Tom London  |525       |2.8721716524875673|17    |203      |2022-04-26 15:26:56|
    |356804|Bud Osborne |515       |2.0389507108727773|15    |149      |2022-04-26 15:26:56|
    +------+------------+----------+------------------+------+---------+-------------------+
  3. Ahora vamos a agregar datos a nuestro modelo para ilustrar una actualización incremental. Añade el actor "Clicky McClickHouse" a la tabla actors:

    INSERT INTO imdb.actors VALUES (845466, 'Clicky', 'McClickHouse', 'M');
  4. Hagamos que "Clicky" protagonice 910 películas al azar:

    INSERT INTO imdb.roles
    SELECT now() as created_at, 845466 as actor_id, id as movie_id, 'Himself' as role
    FROM imdb.movies
    LIMIT 910 OFFSET 10000;
  5. Confirma que ahora sí es el actor con más apariciones consultando directamente la tabla de origen subyacente, sin pasar por ningún modelo de dbt:

    SELECT id,
        any(actor_name)          as name,
        uniqExact(movie_id)    as num_movies,
        avg(rank)                as avg_rank,
        uniqExact(genre)         as unique_genres,
        uniqExact(director_name) as uniq_directors,
        max(created_at)          as updated_at
    FROM (
            SELECT imdb.actors.id                                                   as id,
                    concat(imdb.actors.first_name, ' ', imdb.actors.last_name)       as actor_name,
                    imdb.movies.id as movie_id,
                    imdb.movies.rank                                                 as rank,
                    genre,
                    concat(imdb.directors.first_name, ' ', imdb.directors.last_name) as director_name,
                    created_at
            FROM imdb.actors
                    JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id
                    LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id
                    LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id
                    LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id
                    LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id
            )
    GROUP BY id
    ORDER BY num_movies DESC
    LIMIT 2;
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |id    |name               |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |845466|Clicky McClickHouse|910       |1.4687938697032283|21    |662      |2022-04-26 16:20:36|
    |45332 |Mel Blanc          |909       |5.7884792542982515|19    |148      |2022-04-26 16:17:42|
    +------+-------------------+----------+------------------+------+---------+-------------------+
  6. Ejecuta un dbt run y confirma que nuestro modelo se haya actualizado y coincida con los resultados anteriores:

    clickhouse-user@clickhouse:~/imdb$  dbt run
    16:12:16  Running with dbt=1.1.0
    16:12:16  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics
    16:12:16
    16:12:17  Concurrency: 1 threads (target='dev')
    16:12:17
    16:12:17  1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN]
    16:12:24  1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 6.82s]
    16:12:24
    16:12:24  Finished running 1 incremental model in 7.79s.
    16:12:24
    16:12:24  Completed successfully
    16:12:24
    16:12:24  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
    SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 2;
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |id    |name               |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |845466|Clicky McClickHouse|910       |1.4687938697032283|21    |662      |2022-04-26 16:20:36|
    |45332 |Mel Blanc          |909       |5.7884792542982515|19    |148      |2022-04-26 16:17:42|
    +------+-------------------+----------+------------------+------+---------+-------------------+

Aspectos internos

Podemos identificar las sentencias ejecutadas para realizar la actualización incremental anterior consultando el registro de consultas de ClickHouse.

SELECT event_time, query  FROM system.query_log WHERE type='QueryStart' AND query LIKE '%dbt%'
AND event_time > subtractMinutes(now(), 15) ORDER BY event_time LIMIT 100;

Ajuste la consulta anterior al período de ejecución. Dejamos al usuario la inspección de los resultados, pero destacamos la estrategia general que utiliza el adaptador para realizar actualizaciones incrementales:

  1. El adaptador crea una tabla temporal actor_sumary__dbt_tmp. Las filas que han cambiado se envían a esta tabla.
  2. Se crea una nueva tabla, actor_summary_new,. A continuación, las filas de la tabla anterior se envían de la antigua a la nueva, con una comprobación para asegurarse de que los identificadores de fila no existan en la tabla temporal. Esto resuelve eficazmente las actualizaciones y los duplicados.
  3. Los resultados de la tabla temporal se envían a la nueva tabla actor_summary:
  4. Por último, la nueva tabla se intercambia de forma atómica con la versión anterior mediante una instrucción EXCHANGE TABLES. A su vez, se eliminan la tabla anterior y la temporal.

Esto se muestra a continuación:

actualizaciones incrementales dbt

Esta estrategia puede presentar dificultades en modelos muy grandes. Para obtener más información, consulte Limitaciones.

Estrategia append (modo de solo inserciones)

Para superar las limitaciones de los conjuntos de datos grandes en los modelos incrementales, el adaptador usa el parámetro de configuración de dbt incremental_strategy. Este puede establecerse con el valor append. Cuando se configura así, las filas actualizadas se insertan directamente en la tabla de destino (también conocida como imdb_dbt.actor_summary) y no se crea ninguna tabla temporal. Nota: El modo append-only requiere que tus datos sean inmutables o que los duplicados sean aceptables. Si quieres un modelo de tabla incremental que admita filas modificadas, ¡no uses este modo!

Para ilustrar este modo, agregaremos otro actor nuevo y volveremos a ejecutar dbt run con incremental_strategy='append'.

  1. Configura el modo append-only en actor_summary.sql:

    {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='append') }}
  2. Añadamos otro actor famoso: Danny DeBito

    INSERT INTO imdb.actors VALUES (845467, 'Danny', 'DeBito', 'M');
  3. Hagamos que Danny aparezca en 920 películas aleatorias.

    INSERT INTO imdb.roles
    SELECT now() as created_at, 845467 as actor_id, id as movie_id, 'Himself' as role
    FROM imdb.movies
    LIMIT 920 OFFSET 10000;
  4. Ejecuta dbt run y confirma que Danny se añadió a la tabla actor-summary

    clickhouse-user@clickhouse:~/imdb$ dbt run
    16:12:16  Running with dbt=1.1.0
    16:12:16  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 186 macros, 0 operations, 0 seed files, 6 sources, 0 exposures, 0 metrics
    16:12:16
    16:12:17  Concurrency: 1 threads (target='dev')
    16:12:17
    16:12:17  1 of 1 START incremental model imdb_dbt.actor_summary........................... [RUN]
    16:12:24  1 of 1 OK created incremental model imdb_dbt.actor_summary...................... [OK in 0.17s]
    16:12:24
    16:12:24  Finished running 1 incremental model in 0.19s.
    16:12:24
    16:12:24  Completed successfully
    16:12:24
    16:12:24  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
    SELECT * FROM imdb_dbt.actor_summary ORDER BY num_movies DESC LIMIT 3;
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |id    |name               |num_movies|avg_rank          |genres|directors|updated_at         |
    +------+-------------------+----------+------------------+------+---------+-------------------+
    |845467|Danny DeBito       |920       |1.4768987303293204|21    |670      |2022-04-26 16:22:06|
    |845466|Clicky McClickHouse|910       |1.4687938697032283|21    |662      |2022-04-26 16:20:36|
    |45332 |Mel Blanc          |909       |5.7884792542982515|19    |148      |2022-04-26 16:17:42|
    +------+-------------------+----------+------------------+------+---------+-------------------+

Observa lo mucho más rápida que fue esa ejecución incremental en comparación con la inserción de "Clicky".

Si vuelves a revisar la tabla query_log, verás las diferencias entre las 2 ejecuciones incrementales:

INSERT INTO imdb_dbt.actor_summary ("id", "name", "num_movies", "avg_rank", "genres", "directors", "updated_at")
WITH actor_summary AS (
   SELECT id,
      any(actor_name) AS name,
      uniqExact(movie_id)    AS num_movies,
      avg(rank)                AS avg_rank,
      uniqExact(genre)         AS genres,
      uniqExact(director_name) AS directors,
      max(created_at) AS updated_at
   FROM (
      SELECT imdb.actors.id AS id,
         concat(imdb.actors.first_name, ' ', imdb.actors.last_name) AS actor_name,
         imdb.movies.id AS movie_id,
         imdb.movies.rank AS rank,
         genre,
         concat(imdb.directors.first_name, ' ', imdb.directors.last_name) AS director_name,
         created_at
      FROM imdb.actors
         JOIN imdb.roles ON imdb.roles.actor_id = imdb.actors.id
         LEFT OUTER JOIN imdb.movies ON imdb.movies.id = imdb.roles.movie_id
         LEFT OUTER JOIN imdb.genres ON imdb.genres.movie_id = imdb.movies.id
         LEFT OUTER JOIN imdb.movie_directors ON imdb.movie_directors.movie_id = imdb.movies.id
         LEFT OUTER JOIN imdb.directors ON imdb.directors.id = imdb.movie_directors.director_id
   )
   GROUP BY id
)

SELECT *
FROM actor_summary
-- este filtro solo se aplicará en una ejecución incremental
WHERE id > (SELECT max(id) FROM imdb_dbt.actor_summary) OR updated_at > (SELECT max(updated_at) FROM imdb_dbt.actor_summary)

En esta ejecución, solo se añaden directamente las filas nuevas a la tabla imdb_dbt.actor_summary y no se crea ninguna tabla.

Modo de eliminación e inserción (experimental)

Históricamente, ClickHouse solo ha ofrecido un soporte limitado para las actualizaciones y eliminaciones, en forma de mutaciones. Estas pueden consumir muchísimas operaciones de E/S y, por lo general, conviene evitarlas.

ClickHouse 22.8 introdujo las eliminaciones ligeras y ClickHouse 25.7 introdujo las actualizaciones ligeras. Con la introducción de estas funciones, los cambios realizados mediante consultas de actualización individuales, incluso cuando se materializan de forma asíncrona, se reflejan al instante desde la perspectiva del usuario.

Este modo puede configurarse para un modelo mediante el parámetro incremental_strategy, es decir.

{{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id', incremental_strategy='delete+insert') }}

Esta estrategia opera directamente sobre la tabla del modelo de destino, por lo que, si se produce algún problema durante la operación, es probable que los datos del modelo incremental queden en un estado no válido; no hay actualización atómica.

En resumen, este enfoque:

  1. El adaptador crea una tabla temporal actor_sumary__dbt_tmp. Las filas que han cambiado se envían a esta tabla.
  2. Se ejecuta un DELETE en la tabla actual actor_summary. Las filas se eliminan por id a partir de actor_sumary__dbt_tmp
  3. Las filas de actor_sumary__dbt_tmp se insertan en actor_summary mediante un INSERT INTO actor_summary SELECT * FROM actor_sumary__dbt_tmp.

Este proceso se muestra a continuación:

incremental con eliminación ligera

modo insert_overwrite (experimental)

Realiza los siguientes pasos:

  1. Crea una tabla de staging (temporal) con la misma estructura que la relación del modelo incremental: CREATE TABLE {staging} AS {target}.
  2. Inserta solo los registros nuevos (producidos por SELECT) en la tabla de staging.
  3. Reemplaza solo las particiones nuevas (presentes en la tabla de staging) en la tabla de destino.

Este enfoque tiene las siguientes ventajas:

  • Es más rápido que la estrategia predeterminada porque no copia toda la tabla.
  • Es más seguro que otras estrategias porque no modifica la tabla original hasta que la operación INSERT se completa correctamente: en caso de fallo intermedio, la tabla original no se modifica.
  • Implementa la práctica recomendada en ingeniería de datos de la "inmutabilidad de las particiones", lo que simplifica el procesamiento de datos incremental y en paralelo, los rollbacks, etc.
sobrescritura incremental insert

Crear un snapshot

Los snapshots de dbt permiten mantener un registro de los cambios en un modelo mutable a lo largo del tiempo. Esto, a su vez, permite realizar consultas en un momento determinado sobre los modelos, de modo que los analistas puedan "retroceder en el tiempo" para ver el estado anterior de un modelo. Esto se logra mediante dimensiones de cambio lento de tipo 2, donde las columnas de fecha de inicio y fin registran cuándo una fila era válida. Esta funcionalidad es compatible con el adaptador de ClickHouse y se muestra a continuación.

Este ejemplo asume que has completado Creating an Incremental Table Model. Asegúrate de que tu actor&#95;summary.sql no establezca inserts&#95;only=True. Tu models/actor&#95;summary.sql debería verse así:

   {{ config(order_by='(updated_at, id, name)', engine='MergeTree()', materialized='incremental', unique_key='id') }}

   with actor_summary as (
       SELECT id,
           any(actor_name) as name,
           uniqExact(movie_id)    as num_movies,
           avg(rank)                as avg_rank,
           uniqExact(genre)         as genres,
           uniqExact(director_name) as directors,
           max(created_at) as updated_at
       FROM (
           SELECT {{ source('imdb', 'actors') }}.id as id,
               concat({{ source('imdb', 'actors') }}.first_name, ' ', {{ source('imdb', 'actors') }}.last_name) as actor_name,
               {{ source('imdb', 'movies') }}.id as movie_id,
               {{ source('imdb', 'movies') }}.rank as rank,
               genre,
               concat({{ source('imdb', 'directors') }}.first_name, ' ', {{ source('imdb', 'directors') }}.last_name) as director_name,
               created_at
       FROM {{ source('imdb', 'actors') }}
           JOIN {{ source('imdb', 'roles') }} ON {{ source('imdb', 'roles') }}.actor_id = {{ source('imdb', 'actors') }}.id
           LEFT OUTER JOIN {{ source('imdb', 'movies') }} ON {{ source('imdb', 'movies') }}.id = {{ source('imdb', 'roles') }}.movie_id
           LEFT OUTER JOIN {{ source('imdb', 'genres') }} ON {{ source('imdb', 'genres') }}.movie_id = {{ source('imdb', 'movies') }}.id
           LEFT OUTER JOIN {{ source('imdb', 'movie_directors') }} ON {{ source('imdb', 'movie_directors') }}.movie_id = {{ source('imdb', 'movies') }}.id
           LEFT OUTER JOIN {{ source('imdb', 'directors') }} ON {{ source('imdb', 'directors') }}.id = {{ source('imdb', 'movie_directors') }}.director_id
       )
       GROUP BY id
   )
   select *
   from actor_summary

   {% if is_incremental() %}

   -- este filtro solo se aplicará en una ejecución incremental
   where id > (select max(id) from {{ this }}) or updated_at > (select max(updated_at) from {{this}})

   {% endif %}
  1. Cree un archivo actor_summary en el directorio snapshots.

     touch snapshots/actor_summary.sql
  2. Actualice el contenido del archivo actor_summary.sql con lo siguiente:

    {% snapshot actor_summary_snapshot %}
    
    {{
    config(
    target_schema='snapshots',
    unique_key='id',
    strategy='timestamp',
    updated_at='updated_at',
    )
    }}
    
    select * from {{ref('actor_summary')}}
    
    {% endsnapshot %}

Algunas observaciones sobre este contenido:

  • La consulta select define los resultados de los que desea capturar snapshots a lo largo del tiempo. La función ref se usa para hacer referencia al modelo actor_summary que creamos anteriormente.
  • Necesitamos una columna timestamp para indicar los cambios en los registros. Nuestra columna updated_at (consulte Creación de un modelo de tabla incremental) puede usarse aquí. El parámetro strategy indica que usamos un timestamp para señalar las actualizaciones, mientras que el parámetro updated_at especifica la columna que se debe utilizar. Si esto no está presente en su modelo, también puede usar la estrategia check. Esto es mucho menos eficiente y requiere que el usuario especifique una lista de columnas para comparar. dbt compara los valores actuales e históricos de estas columnas y registra cualquier cambio (o no hace nada si son idénticos).
  1. Ejecuta el comando dbt snapshot.

    clickhouse-user@clickhouse:~/imdb$ dbt snapshot
    13:26:23  Running with dbt=1.1.0
    13:26:23  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics
    13:26:23
    13:26:25  Concurrency: 1 threads (target='dev')
    13:26:25
    13:26:25  1 of 1 START snapshot snapshots.actor_summary_snapshot...................... [RUN]
    13:26:25  1 of 1 OK snapshotted snapshots.actor_summary_snapshot...................... [OK in 0.79s]
    13:26:25
    13:26:25  Finished running 1 snapshot in 2.11s.
    13:26:25
    13:26:25  Completed successfully
    13:26:25
    13:26:25  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1

Observa que se ha creado la tabla actor_summary_snapshot en la base de datos snapshots (determinada por el parámetro target_schema).

  1. Al observar estos datos, verá cómo dbt ha incluido las columnas dbt_valid_from y dbt_valid_to. La última tiene valores nulos. Las ejecuciones posteriores la actualizarán.

    SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;
    +------+----------+------------+----------+-------------------+------------+
    |id    |first_name|last_name   |num_movies|dbt_valid_from     |dbt_valid_to|
    +------+----------+------------+----------+-------------------+------------+
    |845467|Danny     |DeBito      |920       |2022-05-25 19:33:32|NULL        |
    |845466|Clicky    |McClickHouse|910       |2022-05-25 19:32:34|NULL        |
    |45332 |Mel       |Blanc       |909       |2022-05-25 19:31:47|NULL        |
    |621468|Bess      |Flowers     |672       |2022-05-25 19:31:47|NULL        |
    |283127|Tom       |London      |549       |2022-05-25 19:31:47|NULL        |
    +------+----------+------------+----------+-------------------+------------+
  2. Haz que nuestro actor favorito, Clicky McClickHouse, aparezca en otras 10 películas.

    INSERT INTO imdb.roles
    SELECT now() as created_at, 845466 as actor_id, rand(number) % 412320 as movie_id, 'Himself' as role
    FROM system.numbers
    LIMIT 10;
  3. Vuelve a ejecutar el comando dbt run desde el directorio imdb. Esto actualizará el modelo incremental. Una vez completado, ejecuta dbt snapshot para capturar los cambios.

    clickhouse-user@clickhouse:~/imdb$ dbt run
    13:46:14  Running with dbt=1.1.0
    13:46:14  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics
    13:46:14
    13:46:15  Concurrency: 1 threads (target='dev')
    13:46:15
    13:46:15  1 of 1 START incremental model imdb_dbt.actor_summary....................... [RUN]
    13:46:18  1 of 1 OK created incremental model imdb_dbt.actor_summary.................. [OK in 2.76s]
    13:46:18
    13:46:18  Finished running 1 incremental model in 3.73s.
    13:46:18
    13:46:18  Completed successfully
    13:46:18
    13:46:18  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
    
    clickhouse-user@clickhouse:~/imdb$ dbt snapshot
    13:46:26  Running with dbt=1.1.0
    13:46:26  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 0 seed files, 3 sources, 0 exposures, 0 metrics
    13:46:26
    13:46:27  Concurrency: 1 threads (target='dev')
    13:46:27
    13:46:27  1 of 1 START snapshot snapshots.actor_summary_snapshot...................... [RUN]
    13:46:31  1 of 1 OK snapshotted snapshots.actor_summary_snapshot...................... [OK in 4.05s]
    13:46:31
    13:46:31  Finished running 1 snapshot in 5.02s.
    13:46:31
    13:46:31  Completed successfully
    13:46:31
    13:46:31  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
  4. Si ahora consultamos nuestra instantánea, observa que tenemos 2 filas para Clicky McClickHouse. Nuestra entrada anterior ahora tiene un valor en dbt_valid_to. El nuevo valor se registra con ese mismo valor en la columna dbt_valid_from y con un valor dbt_valid_to de null. Si hubiera filas nuevas, estas también se añadirían a la instantánea.

    SELECT id, name, num_movies, dbt_valid_from, dbt_valid_to FROM snapshots.actor_summary_snapshot ORDER BY num_movies DESC LIMIT 5;
    +------+----------+------------+----------+-------------------+-------------------+
    |id    |first_name|last_name   |num_movies|dbt_valid_from     |dbt_valid_to       |
    +------+----------+------------+----------+-------------------+-------------------+
    |845467|Danny     |DeBito      |920       |2022-05-25 19:33:32|NULL               |
    |845466|Clicky    |McClickHouse|920       |2022-05-25 19:34:37|NULL               |
    |845466|Clicky    |McClickHouse|910       |2022-05-25 19:32:34|2022-05-25 19:34:37|
    |45332 |Mel       |Blanc       |909       |2022-05-25 19:31:47|NULL               |
    |621468|Bess      |Flowers     |672       |2022-05-25 19:31:47|NULL               |
    +------+----------+------------+----------+-------------------+-------------------+

Para obtener más información sobre los snapshots de dbt, consulte aquí.

Uso de seeds

dbt permite cargar datos desde archivos CSV. Esta capacidad no es adecuada para cargar exportaciones grandes de una base de datos; está pensada más bien para archivos pequeños que suelen usarse para tablas de códigos y diccionarios, por ejemplo, para asociar códigos de país con nombres de países. Como ejemplo sencillo, generaremos y luego cargaremos una lista de códigos de género mediante la funcionalidad de seed.

  1. Generamos una lista de códigos de género a partir de nuestro conjunto de datos existente. Desde el directorio de dbt, use clickhouse-client para crear el archivo seeds/genre_codes.csv:

    clickhouse-user@clickhouse:~/imdb$ clickhouse-client --password <password> --query
    "SELECT genre, ucase(substring(genre, 1, 3)) as code FROM imdb.genres GROUP BY genre
    LIMIT 100 FORMAT CSVWithNames" > seeds/genre_codes.csv
  2. Ejecute el comando dbt seed. Esto creará una nueva tabla genre_codes en nuestra base de datos imdb_dbt (como se define en la configuración del esquema) con las filas de nuestro archivo CSV.

    clickhouse-user@clickhouse:~/imdb$ dbt seed
    17:03:23  Running with dbt=1.1.0
    17:03:23  Found 1 model, 0 tests, 1 snapshot, 0 analyses, 181 macros, 0 operations, 1 seed file, 6 sources, 0 exposures, 0 metrics
    17:03:23
    17:03:24  Concurrency: 1 threads (target='dev')
    17:03:24
    17:03:24  1 of 1 START seed file imdb_dbt.genre_codes..................................... [RUN]
    17:03:24  1 of 1 OK loaded seed file imdb_dbt.genre_codes................................. [INSERT 21 in 0.65s]
    17:03:24
    17:03:24  Finished running 1 seed in 1.62s.
    17:03:24
    17:03:24  Completed successfully
    17:03:24
    17:03:24  Done. PASS=1 WARN=0 ERROR=0 SKIP=0 TOTAL=1
  3. Confirme que se hayan cargado:

    SELECT * FROM imdb_dbt.genre_codes LIMIT 10;
    +-------+----+
    |genre  |code|
    +-------+----+
    |Drama  |DRA |
    |Romance|ROM |
    |Short  |SHO |
    |Mystery|MYS |
    |Adult  |ADU |
    |Family |FAM |
    
    |Action |ACT |
    |Sci-Fi |SCI |
    |Horror |HOR |
    |War    |WAR |
    +-------+----+=

Más información

Las guías anteriores solo ofrecen una visión general de la funcionalidad de dbt. Se recomienda a los usuarios consultar la excelente documentación de dbt.

Navigation