M08 β Pipeline fim a fim β case completo
DuraΓ§Γ£o: 4h PrΓ©-requisitos: M00-M07 ok. Tudo o que aprendeu junto. Objetivo: entregar um pipeline de produΓ§Γ£o completo, do Azure SQL ao dashboard Power BI, versionado em Git, com agendamento diΓ‘rio e alertas. Esse Γ© o case que vocΓͺ vai mostrar em entrevista.
O case
VocΓͺ Γ© o engenheiro de dados responsΓ‘vel por um data lakehouse de vendas. A fonte Γ© o ERP em Azure SQL (
AdventureWorksLT). O time de BI precisa de um dashboard diΓ‘rio em Power BI com:
- Vendas por mΓͺs.
- Top 10 clientes por receita.
- Ticket mΓ©dio por categoria.
O pipeline deve rodar todo dia Γ s 06h BRT, com atΓ© 30 min de SLA, e enviar e-mail se falhar.
Arquitetura final
ββββββββββββββββββββββββββββββββ β Azure SQL AdventureWorksLT β β SalesLT.Customer β β SalesLT.SalesOrderHeader β β SalesLT.SalesOrderDetail β β SalesLT.Product β ββββββββββ¬βββββββββββββββββββββββ β (1) Copy diΓ‘rio (ADF) βΌ βββββββββββββββββββββββββββββββββββββββ β ADLS Gen2 β BRONZE (parquet, daily) β ββββββββββ¬βββββββββββββββββββββββββββββ β (2) Notebook ingest βΌ ββββββββββββββββββββββββββββββββββββ β silver_prd.adventureworks.* β β - customer, orders, products β β (Delta, tipado, dedup, MERGE) β ββββββββββ¬ββββββββββββββββββββββββββ β (3) Notebook agregaΓ§Γ£o βΌ ββββββββββββββββββββββββββββββββββββ β gold_prd.adventureworks.* β β - fact_sales β β - dim_customer, dim_product, dim_date β ββββββββββ¬ββββββββββββββββββββββββββ β (4) SQL Warehouse expΓ΅e βΌ βββββββββββββββββββββββ β Power BI Dashboard β βββββββββββββββββββββββTudo orquestrado por ADF + monitorado em Monitor + alertas em Action Group.
Parte 1 β Recursos novos para este case
VocΓͺ jΓ‘ tem do M01-M06: RG, Storage, Databricks, ADF, KV, UC, Catalogs silver_* e gold_*. Falta:
1.1 β SQL Warehouse no Databricks (serverless ou pro)
Power BI conecta no Databricks via SQL Warehouse. Crie um Serverless (cobra sΓ³ quando em uso):
$WHOUSE_JSON = @'{ "name": "wh-prd-bi", "cluster_size": "Small", "min_num_clusters": 1, "max_num_clusters": 1, "auto_stop_mins": 10, "enable_serverless_compute": true, "spot_instance_policy": "COST_OPTIMIZED", "warehouse_type": "PRO", "tags": { "custom_tags": [ { "key": "projeto", "value": "de" }, { "key": "ambiente", "value": "prd" } ] }}'@$WHOUSE_JSON | Set-Content warehouse.jsondatabricks warehouses create --json @warehouse.jsonPegue o endpoint:
databricks warehouses list -o json | ConvertFrom-Json | Where-Object name -eq "wh-prd-bi" | Select-Object id, jdbc_urlParte 2 β Estrutura final de tabelas
Silver (3 tabelas)
-- silver_prd.adventureworks.customerCREATE SCHEMA IF NOT EXISTS silver_prd.adventureworks;
CREATE TABLE IF NOT EXISTS silver_prd.adventureworks.customer ( customer_id INT, first_name STRING, last_name STRING, company_name STRING, email STRING, phone STRING, modified_at TIMESTAMP, _silver_ingested_at TIMESTAMP) USING DELTA;
-- silver_prd.adventureworks.sales_order_headerCREATE TABLE IF NOT EXISTS silver_prd.adventureworks.sales_order_header ( sales_order_id INT, customer_id INT, order_date DATE, ship_date DATE, status INT, subtotal DOUBLE, tax_amt DOUBLE, freight DOUBLE, total_due DOUBLE, modified_at TIMESTAMP, _silver_ingested_at TIMESTAMP) USING DELTA PARTITIONED BY (order_date);
-- silver_prd.adventureworks.sales_order_detailCREATE TABLE IF NOT EXISTS silver_prd.adventureworks.sales_order_detail ( sales_order_id INT, sales_order_detail_id INT, product_id INT, order_qty INT, unit_price DOUBLE, line_total DOUBLE, modified_at TIMESTAMP, _silver_ingested_at TIMESTAMP) USING DELTA;
-- silver_prd.adventureworks.productCREATE TABLE IF NOT EXISTS silver_prd.adventureworks.product ( product_id INT, name STRING, color STRING, size STRING, standard_cost DOUBLE, list_price DOUBLE, product_category STRING, modified_at TIMESTAMP, _silver_ingested_at TIMESTAMP) USING DELTA;Gold (estrela)
CREATE SCHEMA IF NOT EXISTS gold_prd.adventureworks;
-- DIM CUSTOMERCREATE TABLE IF NOT EXISTS gold_prd.adventureworks.dim_customer ( customer_sk BIGINT GENERATED ALWAYS AS IDENTITY, customer_id INT, full_name STRING, company_name STRING, email STRING, _scd_valid_from TIMESTAMP, _scd_valid_to TIMESTAMP, _scd_current BOOLEAN) USING DELTA;
-- DIM PRODUCTCREATE TABLE IF NOT EXISTS gold_prd.adventureworks.dim_product ( product_sk BIGINT GENERATED ALWAYS AS IDENTITY, product_id INT, name STRING, color STRING, product_category STRING, list_price DOUBLE) USING DELTA;
-- DIM DATECREATE TABLE IF NOT EXISTS gold_prd.adventureworks.dim_date ( date_key DATE, year INT, quarter INT, month INT, month_name STRING, day INT, weekday INT, is_weekend BOOLEAN) USING DELTA;
-- FACT SALESCREATE TABLE IF NOT EXISTS gold_prd.adventureworks.fact_sales ( sales_order_id INT, sales_order_detail_id INT, date_key DATE, customer_sk BIGINT, product_sk BIGINT, order_qty INT, unit_price DOUBLE, line_total DOUBLE) USING DELTA PARTITIONED BY (date_key);Parte 3 β Notebooks
notebooks/10_ingest_bronze_to_silver.py
PadrΓ£o MERGE (upsert incremental):
# Databricks notebook sourcefrom pyspark.sql import functions as Ffrom delta.tables import DeltaTable
dbutils.widgets.text("storage_account", "")dbutils.widgets.text("catalog", "")dbutils.widgets.text("data_processamento", "")
storage = dbutils.widgets.get("storage_account")catalog = dbutils.widgets.get("catalog")data_proc = dbutils.widgets.get("data_processamento") # YYYY-MM-DD
# COMMAND ----------
# Credenciais (tambΓ©m jΓ‘ config no init script do cluster em prd)for k in ["sp-appid", "sp-secret", "sp-tenant"]: pass # jΓ‘ carregado via cluster config; aqui Γ© sΓ³ ilustrativo
bronze_root = f"abfss://bronze@{storage}.dfs.core.windows.net"
# COMMAND ----------
def merge_bronze_to_silver(table_name: str, key_cols: list[str], select_expr: dict[str, str]): """LΓͺ parquet do bronze do dia, transforma com select_expr, upsert no silver.""" path = f"{bronze_root}/source=adventureworks/schema=salesLT/table={table_name}/ingestion_date={data_proc}/" df = spark.read.parquet(path)
df = df.selectExpr(*[f"{v} AS {k}" for k, v in select_expr.items()]) \ .withColumn("_silver_ingested_at", F.current_timestamp())
target_tbl = f"{catalog}.adventureworks.{table_name}" if not spark.catalog.tableExists(target_tbl): df.write.format("delta").saveAsTable(target_tbl) return df.count(), 0
target = DeltaTable.forName(spark, target_tbl) cond = " AND ".join([f"t.{c} = s.{c}" for c in key_cols]) res = ( target.alias("t") .merge(df.alias("s"), cond) .whenMatchedUpdateAll() .whenNotMatchedInsertAll() .execute() ) return df.count(), res
# COMMAND ----------
cust_total, _ = merge_bronze_to_silver( "customer", key_cols=["customer_id"], select_expr={ "customer_id": "CAST(CustomerID AS INT)", "first_name": "FirstName", "last_name": "LastName", "company_name":"CompanyName", "email": "EmailAddress", "phone": "Phone", "modified_at": "CAST(ModifiedDate AS TIMESTAMP)", })print(f"Customer: {cust_total} linhas processadas.")
# COMMAND ----------
merge_bronze_to_silver( "sales_order_header", key_cols=["sales_order_id"], select_expr={ "sales_order_id": "CAST(SalesOrderID AS INT)", "customer_id": "CAST(CustomerID AS INT)", "order_date": "CAST(OrderDate AS DATE)", "ship_date": "CAST(ShipDate AS DATE)", "status": "CAST(Status AS INT)", "subtotal": "CAST(SubTotal AS DOUBLE)", "tax_amt": "CAST(TaxAmt AS DOUBLE)", "freight": "CAST(Freight AS DOUBLE)", "total_due": "CAST(TotalDue AS DOUBLE)", "modified_at": "CAST(ModifiedDate AS TIMESTAMP)", })
merge_bronze_to_silver( "sales_order_detail", key_cols=["sales_order_id","sales_order_detail_id"], select_expr={ "sales_order_id": "CAST(SalesOrderID AS INT)", "sales_order_detail_id": "CAST(SalesOrderDetailID AS INT)", "product_id": "CAST(ProductID AS INT)", "order_qty": "CAST(OrderQty AS INT)", "unit_price": "CAST(UnitPrice AS DOUBLE)", "line_total": "CAST(LineTotal AS DOUBLE)", "modified_at": "CAST(ModifiedDate AS TIMESTAMP)", })
merge_bronze_to_silver( "product", key_cols=["product_id"], select_expr={ "product_id": "CAST(ProductID AS INT)", "name": "Name", "color": "Color", "size": "Size", "standard_cost": "CAST(StandardCost AS DOUBLE)", "list_price": "CAST(ListPrice AS DOUBLE)", "product_category": "ProductCategoryID", # simplificado; em prod faz lookup "modified_at": "CAST(ModifiedDate AS TIMESTAMP)", })
# COMMAND ----------
# ValidaΓ§Γ£o bΓ‘sicadisplay(spark.sql(f""" SELECT (SELECT COUNT(*) FROM {catalog}.adventureworks.customer) customers, (SELECT COUNT(*) FROM {catalog}.adventureworks.sales_order_header) orders, (SELECT COUNT(*) FROM {catalog}.adventureworks.sales_order_detail) order_items, (SELECT COUNT(*) FROM {catalog}.adventureworks.product) products"""))notebooks/20_silver_to_gold.py
# Databricks notebook sourcefrom pyspark.sql import functions as F
dbutils.widgets.text("silver_catalog", "silver_prd")dbutils.widgets.text("gold_catalog", "gold_prd")S = dbutils.widgets.get("silver_catalog")G = dbutils.widgets.get("gold_catalog")
# COMMAND ----------# MAGIC %md ## dim_date β regenera completa
spark.sql(f""" CREATE OR REPLACE TABLE {G}.adventureworks.dim_date AS WITH calendar AS ( SELECT explode(sequence(to_date('2020-01-01'), to_date('2030-12-31'), interval 1 day)) AS date_key ) SELECT date_key, YEAR(date_key) AS year, QUARTER(date_key) AS quarter, MONTH(date_key) AS month, DATE_FORMAT(date_key, 'MMMM') AS month_name, DAY(date_key) AS day, DAYOFWEEK(date_key) AS weekday, DAYOFWEEK(date_key) IN (1,7) AS is_weekend FROM calendar""")
# COMMAND ----------# MAGIC %md ## dim_customer (SCD1 simplificado)
spark.sql(f""" MERGE INTO {G}.adventureworks.dim_customer t USING ( SELECT customer_id, CONCAT_WS(' ', first_name, last_name) AS full_name, company_name, email, CURRENT_TIMESTAMP() AS _scd_valid_from, CAST(NULL AS TIMESTAMP) AS _scd_valid_to, TRUE AS _scd_current FROM {S}.adventureworks.customer ) s ON t.customer_id = s.customer_id WHEN MATCHED THEN UPDATE SET full_name = s.full_name, company_name = s.company_name, email = s.email WHEN NOT MATCHED THEN INSERT (customer_id, full_name, company_name, email, _scd_valid_from, _scd_valid_to, _scd_current) VALUES (s.customer_id, s.full_name, s.company_name, s.email, s._scd_valid_from, s._scd_valid_to, s._scd_current)""")
# COMMAND ----------# MAGIC %md ## dim_product
spark.sql(f""" MERGE INTO {G}.adventureworks.dim_product t USING ( SELECT product_id, name, color, product_category, list_price FROM {S}.adventureworks.product ) s ON t.product_id = s.product_id WHEN MATCHED THEN UPDATE SET name=s.name, color=s.color, product_category=s.product_category, list_price=s.list_price WHEN NOT MATCHED THEN INSERT (product_id, name, color, product_category, list_price) VALUES (s.product_id, s.name, s.color, s.product_category, s.list_price)""")
# COMMAND ----------# MAGIC %md ## fact_sales (overwrite estratΓ©gico por partiΓ§Γ£o "order_date")
spark.sql(f""" CREATE OR REPLACE TABLE {G}.adventureworks.fact_sales PARTITIONED BY (date_key) AS SELECT h.sales_order_id, d.sales_order_detail_id, h.order_date AS date_key, dc.customer_sk, dp.product_sk, d.order_qty, d.unit_price, d.line_total FROM {S}.adventureworks.sales_order_header h JOIN {S}.adventureworks.sales_order_detail d ON h.sales_order_id = d.sales_order_id JOIN {G}.adventureworks.dim_customer dc ON dc.customer_id = h.customer_id AND dc._scd_current JOIN {G}.adventureworks.dim_product dp ON dp.product_id = d.product_id""")
# COMMAND ----------# MAGIC %md ## OPTIMIZE + ZORDER (performance pro Power BI)
spark.sql(f"OPTIMIZE {G}.adventureworks.fact_sales ZORDER BY (customer_sk, product_sk)")
# COMMAND ----------# MAGIC %md ## ValidaΓ§Γ£o: contagens + KPIs
display(spark.sql(f""" SELECT d.year, d.month, COUNT(*) trips, ROUND(SUM(f.line_total), 2) revenue FROM {G}.adventureworks.fact_sales f JOIN {G}.adventureworks.dim_date d ON f.date_key = d.date_key GROUP BY d.year, d.month ORDER BY 1,2"""))notebooks/30_data_quality.py
# Databricks notebook sourcedbutils.widgets.text("catalog", "silver_prd")C = dbutils.widgets.get("catalog")
checks = [ ("customer sem email", f"SELECT COUNT(*) FROM {C}.adventureworks.customer WHERE email IS NULL", 0), ("orders com total negativo", f"SELECT COUNT(*) FROM {C}.adventureworks.sales_order_header WHERE total_due < 0", 0), ("detail sem header (orfΓ£o)", f""" SELECT COUNT(*) FROM {C}.adventureworks.sales_order_detail d LEFT JOIN {C}.adventureworks.sales_order_header h ON h.sales_order_id = d.sales_order_id WHERE h.sales_order_id IS NULL """, 0),]
falhas = []for name, sql, expected in checks: actual = spark.sql(sql).collect()[0][0] print(f"{name}: esperado <= {expected}, real = {actual}") if actual > expected: falhas.append((name, actual, expected))
if falhas: msg = "Data quality fail:\n" + "\n".join([f"- {n}: {a} > {e}" for n,a,e in falhas]) dbutils.notebook.exit(msg)
print("β
DQ OK")Parte 4 β Job DAB ΓΊnico (resources/case.job.yml)
resources: jobs: aw_diario_e2e: name: aw_diario_e2e schedule: quartz_cron_expression: "0 0 9 * * ?" # 06h BRT timezone_id: UTC pause_status: ${var.bundle_target == "prd" ? "UNPAUSED" : "PAUSED"}
email_notifications: on_failure: [ team.old.schoolll@gmail.com ] no_alert_for_skipped_runs: true
max_concurrent_runs: 1 timeout_seconds: 1800 # 30 min SLA
tasks: - task_key: ingest_bronze_to_silver notebook_task: notebook_path: ../notebooks/10_ingest_bronze_to_silver.py base_parameters: storage_account: ${var.storage_account} catalog: ${var.silver_catalog} data_processamento: "{{job.start_time.iso_date}}" job_cluster_key: small
- task_key: data_quality depends_on: [{ task_key: ingest_bronze_to_silver }] notebook_task: notebook_path: ../notebooks/30_data_quality.py base_parameters: catalog: ${var.silver_catalog} job_cluster_key: small
- task_key: silver_to_gold depends_on: [{ task_key: data_quality }] notebook_task: notebook_path: ../notebooks/20_silver_to_gold.py base_parameters: silver_catalog: ${var.silver_catalog} gold_catalog: ${var.gold_catalog} job_cluster_key: small
job_clusters: - job_cluster_key: small new_cluster: spark_version: "15.4.x-scala2.12" node_type_id: Standard_DS3_v2 num_workers: 0 data_security_mode: SINGLE_USER spark_conf: spark.databricks.cluster.profile: singleNode spark.master: local[*, 4] custom_tags: projeto: de ambiente: ${bundle.target} case: aw_e2eParte 5 β ADF orquestra a Copy + dispara o job DAB
Atualize o pipeline ADF (pl_aw_diario_e2e):
- ForEach sobre uma lista de tabelas
[Customer, SalesOrderHeader, SalesOrderDetail, Product]:- Cada iteraΓ§Γ£o: Copy de
SalesLT.<tabela>βbronze/source=adventureworks/schema=salesLT/table=<tabela>/ingestion_date=@{utcNow:yyyy-MM-dd}/.
- Cada iteraΓ§Γ£o: Copy de
- Depois do ForEach: Databricks Job activity (nΓ£o Notebook) β dispara o job
aw_diario_e2epor nome/ID.
A activity βDatabricks Jobβ usa a API
/jobs/run-now. Permite passarnotebook_paramsse quiser sobrescrever. Diferente da βNotebook activityβ que sobe cluster do zero.
Parte 6 β Power BI
6.1 β Instalar conector Databricks (uma vez)
Power BI Desktop β Get Data β Azure Databricks (vem nativo).
6.2 β Conectar
- Server hostname:
adb-xxxxxxx.xx.azuredatabricks.net. - HTTP path: do warehouse
wh-prd-biβ painel SQL Warehouses β seu warehouse β Connection details β copia. - Authentication: AAD (Microsoft account).
- Catalog:
gold_prd. - Schema:
adventureworks.
Importe fact_sales, dim_customer, dim_product, dim_date. Storage mode: Direct Query (nΓ£o importa tudo; usa o warehouse pra cada consulta).
6.3 β Modelo estrela
No Power BI, garanta:
fact_sales[date_key]βdim_date[date_key].fact_sales[customer_sk]βdim_customer[customer_sk].fact_sales[product_sk]βdim_product[product_sk].- Cardinalidades: muitos pra um, single direction.
6.4 β Medidas DAX
Revenue = SUMX(fact_sales, fact_sales[order_qty] * fact_sales[unit_price])Avg Ticket = DIVIDE(SUM(fact_sales[line_total]), DISTINCTCOUNT(fact_sales[sales_order_id]))YoY Revenue % = VAR cur = [Revenue] VAR prev = CALCULATE([Revenue], SAMEPERIODLASTYEAR(dim_date[date_key])) RETURN DIVIDE(cur - prev, prev)6.5 β VisualizaΓ§Γ΅es
- Card: Revenue total, Avg Ticket.
- Line chart: Revenue por mΓͺs (eixo: dim_date.month_name).
- Bar chart: Top 10 clientes por revenue.
- Bar chart: Avg Ticket por product_category.
6.6 β Publicar
Power BI Service β workspace β Publish. Configure refresh agendado (apΓ³s o job das 06h BRT, ex.: 06h30) para garantir dado fresco.
Parte 7 β Monitoramento + alertas
7.1 β Action Group (Azure Monitor)
az monitor action-group create ` --resource-group $RG ` --name ag-data-alerts ` --short-name dataalerts ` --email-receivers name=eu email=team.old.schoolll@gmail.com7.2 β Alerta de falha de Job Databricks
Atalho: o email_notifications.on_failure no DAB jΓ‘ cobre. Para sofisticar:
- Workspace β Jobs β seu job β Edit alerts β adicione webhook (Slack/Teams), notificaΓ§Γ£o por SLA exceeded.
7.3 β Alerta de ADF
ADF β Alerts β + New β mΓ©trica PipelineFailedRuns > 0, frequΓͺncia 5 min, action group ag-data-alerts.
7.4 β Lakehouse Monitor (opcional, premium)
Databricks tem Lakehouse Monitoring: estatΓsticas + drift por tabela. Ative na fact_sales:
CREATE MONITORING FOR TABLE gold_prd.adventureworks.fact_sales PROFILE TYPE TIME_SERIES ( TIMESTAMP_COL_EXPR = date_key, GRANULARITIES = (MONTH) ) SCHEDULE EVERY 1 DAY AT 07:00 TIMEZONE 'America/Sao_Paulo';Parte 8 β Custo final estimado (mΓͺs, dev contido)
| Componente | Custo aprox / mΓͺs |
|---|---|
| ADLS Gen2 (50 GB Hot + 100 GB Cool) | USD 1.20 |
| Azure SQL Serverless (sample, auto-pause) | USD 1-2 |
| ADF (30 execuΓ§Γ΅es diΓ‘rias) | USD 0.40 |
| Databricks Job Cluster (Single Node, 15 min/dia Γ 30) | USD 7 |
| SQL Warehouse Pro Serverless (1h ativo/dia) | USD 10 |
| Key Vault, monitor, logs | USD 1 |
| Total | ~USD 20-25/mΓͺs |
Cabe nos USD 200 do free tier por 8 meses.
Parte 9 β Como contar este case em entrevista
Use STAR:
SituaΓ§Γ£o: βTime de BI usava extraΓ§Γ΅es manuais Excel da base SQL. Quebrava semanalmente, sem histΓ³rico.β
Tarefa: βConstruir lakehouse end-to-end com refresh diΓ‘rio, governanΓ§a e dashboards confiΓ‘veis.β
AΓ§Γ£o:
- Modelei medallion (bronze raw, silver tipado/dedup, gold estrela).
- IngestΓ£o: ADF Copy diΓ‘rio do SQL para ADLS Gen2 particionado por data.
- TransformaΓ§Γ£o: notebooks PySpark com MERGE upsert no silver, agregaΓ§Γ£o em star schema no gold. Tudo Delta.
- GovernanΓ§a: Unity Catalog (catΓ‘logos por camada, external locations, grants por grupo, row filter na visΓ£o de PII para analistas).
- CI/CD: Databricks Asset Bundles versionados em GitHub, GH Actions deploy automΓ‘tico em dev e gated em prd.
- OrquestraΓ§Γ£o: ADF dispara o job multi-task (ingest β DQ check β transform). Falha em DQ aborta downstream.
- Consumo: SQL Warehouse Serverless + Power BI Direct Query.
- Observabilidade: email on failure, ADF alerts, Lakehouse Monitor.
Resultado:
- Dashboard atualizado em < 30 min apΓ³s meia-noite.
- Custo USD ~25/mΓͺs.
- 0 incidentes de qualidade no 1ΒΊ mΓͺs (DQ check derrubando antes do gold).
- Lineage UC documenta cada coluna do dashboard atΓ© a fonte β audit ready.
Pegadinhas finais
- Job multi-task no DAB: cada task tem
job_cluster_key. Mesmas keys = mesmo cluster reaproveitado (mais barato). Keys diferentes = clusters separados (isolado, mais caro). {{job.start_time.iso_date}}: macro do Databricks Job β passa a data no formato YYYY-MM-DD. Use nodata_processamento.- Power BI conectado em catΓ‘logo errado: usuΓ‘rio tΓpico vΓͺ dados de dev por engano. Use SQL Warehouse separado por ambiente.
OPTIMIZEdurante leitura ativa: pode causar pequena latΓͺncia. Rode antes do horΓ‘rio de pico do BI.MERGEem tabela sem partiΓ§Γ΅es/ZORDER nas chaves: full scan β lento. Sempre Z-order pela chave de merge.
Checklist final da trilha
- Pipeline rodou pelo menos 1 vez end-to-end em dev.
- Dashboard Power BI mostra os 3 KPIs do briefing.
- RepositΓ³rio Git com
databricks.yml, notebooks, workflowdeploy.yml. - Tabelas registradas em Unity Catalog (silver_prd e gold_prd).
- Alertas: email on failure configurado, ADF alert criado.
- VocΓͺ consegue explicar em 5 minutos todo o pipeline desenhando no papel.
- VocΓͺ descreveu o case STAR em atΓ© 3 minutos.
E agora?
VocΓͺ terminou a trilha. Para subir o nΓvel:
- Substitua o Single Node por cluster com workers e meΓ§a o ganho num dataset 10x.
- Adicione Streaming: Event Hubs β Auto Loader β silver streaming.
- DLT (Delta Live Tables): refatore o silver/gold como DLT pipeline e veja a comparaΓ§Γ£o.
- Tire DP-203 ou DP-700.
- Tire Databricks DE Associate.
- Publique este repositΓ³rio como case pΓΊblico no LinkedIn (sem secrets, claro).
Boa carreira de DE Sr. π