Snowflake MigrationClickHouse Workshops

Superset no Snowflake

Criação dos três dashboards operacionais do ambiente de origem: conexão, conjuntos de dados, gráficos e montagem.

Este guia apresenta a criação dos três dashboards no Apache Superset em http://localhost:8088 (admin / admin).

Ordem das operações:

  1. Iniciar o Superset e registrar a conexão com o Snowflake
  2. Criar todos os conjuntos de dados (consultas SQL salvas com um nome)
  3. Criar os gráficos e montar os dashboards

Etapa 1: iniciar o Superset e conectar-se ao Snowflake

Iniciar o Superset

A imagem do Superset foi personalizada para incluir os drivers do Snowflake e do ClickHouse. Use --build na primeira execução para que o Docker a crie:

cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake/superset"
source ../.env
docker compose up -d --build

Registrar a conexão com o banco de dados (processo automático)

No diretório superset/, execute:

source ../.env && ./init_superset.sh

O script aguarda até o Superset estar pronto e registra automaticamente NYC Taxi — Snowflake (Source). Saída esperada:

>>> Superset is up.
>>> Authenticated.
>>> CSRF token obtained.
>>> Registering: NYC Taxi — Snowflake (Source)
    Registered successfully.

Registrar a conexão com o banco de dados (alternativa manual)

Se preferir fazer o registro pela interface:

  1. Acesse Settings → Database Connections → + Database
  2. Selecione Snowflake
  3. Preencha a URI do SQLAlchemy — aplique codificação de URL a todos os caracteres especiais da senha (# → %23, ! → %21, @ → %40 etc.):
snowflake://<USER>:<URL_ENCODED_PASSWORD>@<SNOWFLAKE_ORG>-<SNOWFLAKE_ACCOUNT>/NYC_TAXI_DB/ANALYTICS?warehouse=ANALYTICS_WH&role=ANALYST_ROLE
  1. Defina Display Name como: NYC Taxi — Snowflake (Source)
  2. Em Advanced → SQL Lab, ative Allow this database to be explored e Allow DML
  3. Clique em Test Connection → a mensagem "Connection looks good!" deve aparecer
  4. Clique em Connect

Etapa 2: criar todos os conjuntos de dados

Todos os gráficos usam conjuntos de dados virtuais — consultas SQL salvas com um nome.

Como criar cada conjunto de dados:

  1. Acesse Datasets → + Dataset
  2. Selecione o banco de dados: NYC Taxi — Snowflake (Source)
  3. Clique em Create dataset from SQL query e cole o SQL abaixo
  4. Salve com o nome indicado
  5. Depois de salvar: acesse Datasets → ícone de lápis → guia Columns → "Sync columns from source" → Save. Sem essa etapa, o editor de gráficos mostrará 0 colunas.

Conjuntos de dados do dashboard 1

ops_hourly_revenue — Receita por hora e por borough

Esquema: ANALYTICS

SELECT
    DATE_TRUNC('hour', pickup_at)                      AS hour_bucket,
    pickup_borough,
    COUNT(*)                                           AS trip_count,
    SUM(total_amount_usd)                              AS total_revenue,
    AVG(tip_amount_usd / NULLIF(fare_amount_usd, 0))  AS avg_tip_rate,
    AVG(trip_distance_miles)                           AS avg_distance_miles
FROM ANALYTICS.FACT_TRIPS
WHERE pickup_at >= DATEADD('day', -7, CURRENT_TIMESTAMP())
  AND pickup_borough IS NOT NULL
GROUP BY 1, 2
ORDER BY 1 DESC, total_revenue DESC

ops_zone_agg — Agregações por zona

Esquema: ANALYTICS

SELECT
    hour_bucket,
    zone_id,
    trips,
    revenue,
    avg_distance
FROM ANALYTICS.AGG_HOURLY_ZONE_TRIPS
WHERE hour_bucket >= DATEADD('day', -7, CURRENT_TIMESTAMP())

ops_payment_split — Divisão por tipo de pagamento

Esquema: ANALYTICS

SELECT
    payment_type,
    COUNT(*)              AS trip_count,
    SUM(total_amount_usd) AS total_revenue
FROM ANALYTICS.FACT_TRIPS
WHERE pickup_at >= DATEADD('day', -7, CURRENT_TIMESTAMP())
GROUP BY 1

Conjuntos de dados do dashboard 2

exec_rolling_avg — Médias móveis de 7 dias

Esquema: ANALYTICS

SELECT
    pickup_at::DATE                                          AS trip_date,
    COUNT(*)                                                 AS daily_trip_count,
    AVG(trip_distance_miles)                                 AS daily_avg_distance,
    AVG(AVG(trip_distance_miles)) OVER (
        ORDER BY pickup_at::DATE
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    )                                                        AS rolling_7d_avg_distance,
    SUM(total_amount_usd)                                    AS daily_revenue,
    SUM(SUM(total_amount_usd)) OVER (
        ORDER BY pickup_at::DATE
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    )                                                        AS rolling_7d_revenue
FROM ANALYTICS.FACT_TRIPS
GROUP BY 1
ORDER BY 1 DESC
LIMIT 365

exec_top_trips — 10 corridas de maior valor por borough

Esquema: ANALYTICS

Usa QUALIFY do Snowflake — um dos principais desafios da migração. A reescrita no ClickHouse exige uma subconsulta.

SELECT
    trip_id,
    pickup_at,
    pickup_borough,
    total_amount_usd,
    tip_amount_usd,
    trip_distance_miles,
    ROW_NUMBER() OVER (
        PARTITION BY pickup_borough
        ORDER BY total_amount_usd DESC
    ) AS rank_in_borough
FROM ANALYTICS.FACT_TRIPS
WHERE pickup_at::DATE = CURRENT_DATE() - 1
QUALIFY rank_in_borough <= 10
ORDER BY pickup_borough, rank_in_borough

exec_surge — Impacto do preço dinâmico

Esquema: ANALYTICS

SELECT
    CASE
        WHEN surge_multiplier >= 2.0 THEN 'High Surge (2x+)'
        WHEN surge_multiplier >= 1.5 THEN 'Medium Surge (1.5–2x)'
        WHEN surge_multiplier > 1.0  THEN 'Low Surge (1–1.5x)'
        ELSE 'No Surge (1x)'
    END                                    AS surge_category,
    COUNT(*)                               AS trip_count,
    ROUND(AVG(total_amount_usd), 2)        AS avg_total_fare,
    ROUND(AVG(fare_amount_usd), 2)         AS avg_base_fare,
    ROUND(AVG(surge_multiplier), 2)        AS avg_surge
FROM ANALYTICS.FACT_TRIPS
WHERE surge_multiplier IS NOT NULL
GROUP BY 1
ORDER BY avg_surge DESC

Conjuntos de dados do dashboard 3

dqa_rating_dist — Distribuição das avaliações de motoristas

Esquema: RAW ← altere este valor ao criar o conjunto de dados

Consulta RAW.TRIPS_RAW diretamente por meio da sintaxe de caminho com dois-pontos de VARIANT. Essa é a consulta intencionalmente lenta — o destino do benchmark no ClickHouse.

SELECT
    ROUND(TRIP_METADATA:driver.rating::FLOAT, 1)                           AS rating_bucket,
    COUNT(*)                                                               AS trip_count,
    ROUND(AVG(TOTAL_AMOUNT), 2)                                            AS avg_fare,
    ROUND(AVG(DATEDIFF('minute', PICKUP_DATETIME, DROPOFF_DATETIME)), 1)   AS avg_duration_minutes
FROM RAW.TRIPS_RAW
WHERE TRIP_METADATA:driver IS NOT NULL
  AND TRIP_METADATA:driver.rating IS NOT NULL
GROUP BY 1
ORDER BY 1

dqa_vehicle — Receita por tipo de veículo

Esquema: ANALYTICS

SELECT
    vehicle_type,
    COUNT(*)                 AS trip_count,
    SUM(total_amount_usd)    AS total_revenue,
    AVG(total_amount_usd)    AS avg_fare,
    AVG(trip_distance_miles) AS avg_distance
FROM ANALYTICS.FACT_TRIPS
WHERE vehicle_type IS NOT NULL
GROUP BY 1
ORDER BY total_revenue DESC

dqa_traffic — Nível de trânsito versus duração da corrida

Esquema: ANALYTICS

SELECT
    traffic_level,
    COUNT(*)                   AS trip_count,
    AVG(duration_minutes)      AS avg_duration_minutes,
    AVG(trip_distance_miles)   AS avg_distance_miles,
    AVG(total_amount_usd)      AS avg_fare
FROM ANALYTICS.FACT_TRIPS
WHERE traffic_level IS NOT NULL
GROUP BY 1
ORDER BY avg_duration_minutes DESC

dqa_platform — Tendências por plataforma do aplicativo

Esquema: ANALYTICS

SELECT
    pickup_at::DATE       AS trip_date,
    app_platform,
    COUNT(*)              AS trip_count,
    AVG(surge_multiplier) AS avg_surge
FROM ANALYTICS.FACT_TRIPS
WHERE app_platform IS NOT NULL
  AND pickup_at >= DATEADD('day', -30, CURRENT_TIMESTAMP())
GROUP BY 1, 2
ORDER BY 1 DESC

Etapa 3: criar os dashboards

Agora os 10 conjuntos de dados estão prontos. Crie os gráficos e adicione-os aos dashboards.


Dashboard 1: Operations Command Center

Finalidade: visão operacional em tempo real dos 7 dias anteriores. Este é o primeiro dashboard que os parceiros redirecionam ao ClickHouse na Parte 2.

Criar o dashboard:

  1. Dashboards → + Dashboard
  2. Título: Operations Command Center
  3. Atualização automática: a cada 15 minutos (··· → Edit dashboard → Auto-refresh)

Gráfico 1: Trips per Hour (gráfico de linhas)

  • Chart type: Line Chart
  • Dataset: ops_hourly_revenue
  • X-axis: hour_bucket
  • Metrics: SUM(trip_count)
  • Series: pickup_borough
  • Title: Trips per Hour — Last 7 Days

Gráfico 2: Revenue by Borough (gráfico de barras)

  • Chart type: Bar Chart
  • Dataset: ops_hourly_revenue
  • X-axis: pickup_borough
  • Metrics: SUM(total_revenue)
  • Sort: ordem decrescente pela métrica
  • Title: Total Revenue by Borough — Last 7 Days

Gráfico 3: Payment Type Split (gráfico de pizza)

  • Chart type: Pie Chart
  • Dataset: ops_payment_split
  • Dimension: payment_type
  • Metric: SUM(trip_count)
  • Show labels: ativado
  • Title: Trip Count by Payment Type

Gráfico 4: Total Trips (número grande)

  • Chart type: Big Number with Trendline
  • Dataset: ops_hourly_revenue
  • Metric: SUM(trip_count)
  • Title: Total Trips (Last 7 Days)

Gráfico 5: Borough Performance Summary (tabela)

  • Chart type: Table
  • Dataset: ops_hourly_revenue
  • Columns: pickup_borough, SUM(trip_count), SUM(total_revenue), AVG(avg_tip_rate)
  • Row limit: 10
  • Sort: SUM(total_revenue) em ordem decrescente
  • Title: Borough Performance Summary

Layout:

[ Total Trips — Big Number ]  [ Total Revenue — Big Number (add 2nd)  ]
[ Trips per Hour — Line chart (full width)                            ]
[ Revenue by Borough — Bar ]  [ Payment Type Split — Pie             ]
[ Borough Performance — Table (full width)                            ]

Dashboard 2: Executive Weekly Report

Finalidade: visão estratégica para a análise semanal do negócio. Demonstra funções de janela e a sintaxe específica do Snowflake (QUALIFY), que precisa ser reescrita no ClickHouse.

Criar o dashboard:

  1. Dashboards → + Dashboard
  2. Título: Executive Weekly Report
  3. Atualização automática: 1 hora

Gráfico 6: Rolling 7-Day Revenue Trend (gráfico de linhas)

  • Chart type: Line Chart
  • Dataset: exec_rolling_avg
  • X-axis: trip_date
  • Metrics: MAX(daily_revenue), MAX(rolling_7d_revenue)
  • Title: Daily Revenue with 7-Day Rolling Average

Gráfico 7a: Daily Trip Volume (número grande)

  • Chart type: Big Number with Trendline
  • Dataset: exec_rolling_avg
  • Metric: MAX(daily_trip_count)
  • Title: Daily Trip Volume (Last Year)

Gráfico 7b: Rolling 7-Day Average Distance (gráfico de linhas)

  • Chart type: Line Chart
  • Dataset: exec_rolling_avg
  • X-axis: trip_date
  • Metrics: MAX(rolling_7d_avg_distance)
  • Title: Rolling 7-Day Average Distance (miles)

Gráfico 8: Top 10 Trips per Borough (tabela)

  • Chart type: Table
  • Dataset: exec_top_trips
  • Query Mode: RAW RECORDS ← importante: o conjunto de dados usa QUALIFY, portanto o Superset não deve agregar novamente
  • Columns: pickup_borough, rank_in_borough, total_amount_usd, tip_amount_usd, trip_distance_miles, pickup_at
  • Sort By: total_amount_usd em ordem decrescente
  • Row limit: 60
  • Title: Top 10 Trips per Borough — Yesterday
  • Observação: usa QUALIFY — específico do Snowflake; precisa ser reescrito como subconsulta no ClickHouse

Gráfico 9: Surge Pricing Breakdown (gráfico misto)

  • Chart type: Mixed Chart ← use este, não Bar Chart; Bar Chart não oferece um eixo secundário
  • Dataset: exec_surge
  • X-axis: surge_category
  • Query A — Bar: métrica SUM(trip_count), rótulo Trip Count
  • Query B — Line: métrica MAX(avg_total_fare), rótulo Avg Total Fare, eixo Y: Right
  • Sort: SUM(trip_count) em ordem decrescente
  • Title: Trip Volume and Average Fare by Surge Category

Gráfico 10: Surge Distribution (gráfico de pizza)

  • Chart type: Pie Chart
  • Dataset: exec_surge
  • Dimension: surge_category
  • Metric: SUM(trip_count)
  • Title: Surge Pricing Distribution

Layout:

[ Rolling Revenue — Line chart (full width)                              ]
[ Daily Trip Volume — Big Number (50%) ]  [ Avg Distance — Line (50%)   ]
[ Top 10 Trips — Table (60%) ]  [ Surge Distribution — Pie (40%)        ]
[ Surge Breakdown — Bar chart (full width)                               ]

Dashboard 3: Driver & Quality Analytics

Finalidade: análise detalhada do desempenho dos motoristas e da qualidade das corridas. É intencionalmente o dashboard mais lento — consulta RAW.TRIPS_RAW diretamente por meio do acesso VARIANT. Registre aqui o tempo da consulta como referência para o benchmark de desempenho do ClickHouse na Parte 2.

Criar o dashboard:

  1. Dashboards → + Dashboard
  2. Título: Driver & Quality Analytics
  3. Atualização automática: 1 hora

Gráfico 11: Trip Count by Driver Rating (gráfico de barras)

  • Chart type: Bar Chart
  • Dataset: dqa_rating_dist
  • X-axis: rating_bucket
  • Metrics: SUM(trip_count)
  • Title: Trip Count by Driver Rating
  • Observação: varre RAW.TRIPS_RAW com acesso VARIANT — observe o tempo de consulta em comparação com o ClickHouse

Gráfico 12: Average Fare by Rating (gráfico de linhas)

  • Chart type: Line Chart
  • Dataset: dqa_rating_dist
  • X-axis: rating_bucket
  • Metrics: MAX(avg_fare)
  • Title: Average Fare by Driver Rating

Gráfico 13: Revenue by Vehicle Type (barras horizontais)

  • Chart type: Bar Chart (horizontal)
  • Dataset: dqa_vehicle
  • X-axis: vehicle_type
  • Metrics: SUM(total_revenue), SUM(trip_count) (eixo secundário)
  • Title: Revenue and Trip Count by Vehicle Type

Gráfico 14: Traffic Level Impact (gráfico de barras)

  • Chart type: Bar Chart
  • Dataset: dqa_traffic
  • X-axis: traffic_level
  • Metrics: MAX(avg_duration_minutes), MAX(avg_distance_miles) (eixo secundário)
  • Title: Average Trip Duration and Distance by Traffic Level

Gráfico 15: Daily Trips by App Platform (gráfico de linhas)

  • Chart type: Line Chart
  • Dataset: dqa_platform
  • X-axis: trip_date
  • Metrics: SUM(trip_count)
  • Series: app_platform
  • Title: Daily Trips by App Platform — Last 30 Days

Gráfico 16: Surge by Platform (tabela)

  • Chart type: Table
  • Dataset: dqa_platform
  • Columns: app_platform, SUM(trip_count), AVG(avg_surge)
  • Row limit: 10
  • Title: Surge by Platform

Layout:

[ Trip Count by Rating — Bar ]  [ Avg Fare by Rating — Line            ]
[ Revenue by Vehicle Type — Horizontal bar (full width)                ]
[ Traffic Level Impact — Bar (50%) ]  [ Surge by Platform — Table (50%)]
[ Daily Trips by Platform — Line chart (full width)                    ]

Etapa 4: verificar

  1. Abra cada dashboard e confirme que todos os gráficos são carregados sem erros
  2. Para o dashboard 3, anote o tempo de execução da consulta dqa_rating_dist em Snowflake UI → Activity → Query History — guarde-o como benchmark da migração

Gráfico do Superset que mostra a distribuição das avaliações de motoristas no conjunto de dados do Snowflake, concentrada entre 4,0 e 5,0

Etapa 5: exportar para reutilização

Depois de concluir os dashboards, exporte-os para permitir a importação automática em execuções futuras:

  1. Abra cada dashboard → ··· → Export (salva como .zip)
  2. Coloque os arquivos em superset/dashboards/:
    • 01_operations_command_center.zip
    • 02_executive_weekly_report.zip
    • 03_driver_quality_analytics.zip
  3. Execute novamente ./init_superset.sh — nas próximas preparações, ele os importará automaticamente

Importante — credenciais de exemplo nos ZIPs incluídos no repositório.

A conexão com o banco de dados em databases/*.yaml de cada *.zip usa valores de exemplo no lugar dos dados reais:

sqlalchemy_uri: snowflake://LAB_USER:XXXXXXXXXX@MYORG-MYACCOUNT/NYC_TAXI_DB/ANALYTICS?role=ANALYST_ROLE&warehouse=ANALYTICS_WH
  • Importação automática (./init_superset.sh) — funciona sem alterações. Antes da importação, o script registra a conexão real do Snowflake com os valores de .env e, após cada importação, reaplica a URI correta (veja _update_db em init_superset.sh); assim, os valores de exemplo são substituídos por suas credenciais reais.
  • Importação manual pela interface do Superset — o banco importado será criado com a URI de exemplo e não conseguirá se conectar. Após a importação, acesse Settings → Database Connections → Edit e substitua sqlalchemy_uri pela URI real do Snowflake (por exemplo, snowflake://<USER>:<PASSWORD>@<ORG>-<ACCOUNT>/NYC_TAXI_DB/ANALYTICS?role=ANALYST_ROLE&warehouse=ANALYTICS_WH).
  • Nova exportação de seus próprios dashboards — durante a exportação, o Superset incorpora o localizador da conta e o nome de usuário em databases/*.yaml. Antes de fazer commit dos ZIPs exportados novamente, substitua esses valores por MYORG-MYACCOUNT / LAB_USER, para que os identificadores da conta não vazem para o histórico do Git.

Nesta página

Etapa 1: iniciar o Superset e conectar-se ao SnowflakeIniciar o SupersetRegistrar a conexão com o banco de dados (processo automático)Registrar a conexão com o banco de dados (alternativa manual)Etapa 2: criar todos os conjuntos de dadosConjuntos de dados do dashboard 1ops_hourly_revenue — Receita por hora e por boroughops_zone_agg — Agregações por zonaops_payment_split — Divisão por tipo de pagamentoConjuntos de dados do dashboard 2exec_rolling_avg — Médias móveis de 7 diasexec_top_trips — 10 corridas de maior valor por boroughexec_surge — Impacto do preço dinâmicoConjuntos de dados do dashboard 3dqa_rating_dist — Distribuição das avaliações de motoristasdqa_vehicle — Receita por tipo de veículodqa_traffic — Nível de trânsito versus duração da corridadqa_platform — Tendências por plataforma do aplicativoEtapa 3: criar os dashboardsDashboard 1: Operations Command CenterGráfico 1: Trips per Hour (gráfico de linhas)Gráfico 2: Revenue by Borough (gráfico de barras)Gráfico 3: Payment Type Split (gráfico de pizza)Gráfico 4: Total Trips (número grande)Gráfico 5: Borough Performance Summary (tabela)Dashboard 2: Executive Weekly ReportGráfico 6: Rolling 7-Day Revenue Trend (gráfico de linhas)Gráfico 7a: Daily Trip Volume (número grande)Gráfico 7b: Rolling 7-Day Average Distance (gráfico de linhas)Gráfico 8: Top 10 Trips per Borough (tabela)Gráfico 9: Surge Pricing Breakdown (gráfico misto)Gráfico 10: Surge Distribution (gráfico de pizza)Dashboard 3: Driver & Quality AnalyticsGráfico 11: Trip Count by Driver Rating (gráfico de barras)Gráfico 12: Average Fare by Rating (gráfico de linhas)Gráfico 13: Revenue by Vehicle Type (barras horizontais)Gráfico 14: Traffic Level Impact (gráfico de barras)Gráfico 15: Daily Trips by App Platform (gráfico de linhas)Gráfico 16: Surge by Platform (tabela)Etapa 4: verificarEtapa 5: exportar para reutilização
PT