Teste contratos em adaptadores
Define ingestion intent once. Run it natively anywhere.
Esta página mostra a ingestão do medalhão USGS GeoJSON reutilizada no Databricks, AWS, Snowflake, Fabric e GCP. O contrato definido mantém a intenção do negócio, regras de qualidade, comportamento de gravação e resultados do medalhão são iguais. Os poucos diferenças são parâmetros de contrato necessários para vincular a mesma intenção a cada fonte nativa do adaptador, nomes de tabelas, referências SQL e opções de armazenamento.
O objetivo desta página é a reutilização do contrato: a mesma família de contratos medalhão é transportado entre adaptadores e apenas as ligações mínimas da plataforma mudam.
Conjunto de contratos reutilizados
| Contrato | Shared ingestion intent |
|---|---|
bronze_usgs_geojson.ingestion.yaml | Leia a carga útil USGS de 2,5 dias do GeoJSON em uma linha de resposta bruta com raw_response e response_page_number. |
silver_usgs_events.ingestion.yaml | Analise features[], produza uma linha por evento de terremoto, derive campos de eventos, filtre IDs de eventos inválidos e desduplicar por earthquake_id. |
gold_usgs_daily_summary.ingestion.yaml | Agregue eventos de prata por event_date com contagens de eventos, contagens de tsunami, métricas de magnitude/profundidade, redes de relatórios e tempo de atualização mais recente. |
gold_usgs_magnitude_bands.ingestion.yaml | Agregue eventos prata por magnitude_band e event_type com contagens de eventos, métricas de magnitude e horários do primeiro/último evento. |
Parâmetros de Contrato Compartilhados
| Parameter group | O conteúdo permaneceu o mesmo |
|---|---|
| Ordem de execução | bronze_usgs_geojson, silver_usgs_events, gold_usgs_daily_summary, gold_usgs_magnitude_bands. |
| Carga útil de origem | USGS 2.5_day.geojson feed de terremoto para a mesma janela de data e filtros. |
| Comportamento de gravação Bronze | layer: bronze, mode: overwrite, schema_policy: permissive. |
| Regras de qualidade Bronze | required_columns: [raw_response, response_page_number], not_null: [raw_response], unique_key: [response_page_number]. |
| Comportamento de gravação prateada | layer: silver, mode: overwrite, schema_policy: additive_only. |
| Silver transformation intent | Forme um evento por item features[], padronize carimbos de data e hora e coordenadas, derive event_date, magnitude_band e is_tsunami_related, filtre earthquake_id IS NOT NULL, desduplicar por earthquake_id. |
| Regras de qualidade de prata | not_null: [earthquake_id, event_time, latitude, longitude], unique_key: [earthquake_id], expressões de validação de coordenadas/profundidade/magnitude. |
| Comportamento de gravação de ouro | layer: gold, mode: overwrite, schema_policy: additive_only. |
| Regras de qualidade de ouro | Daily summary requires event_date; magnitude bands requires magnitude_band. |
| Linhas de saída esperadas | Bronze 1, silver 30, gold daily 2, gold magnitude bands 3. |
Conteúdo do contrato compartilhado
Os trechos abaixo mostram o conteúdo do contrato que é reutilizado, não apenas o diferenças específicas do adaptador. Igualdade exata significa que o bloco YAML é copiado inalterado nos adaptadores nomeados. Igualdade normalizada significa apenas tabela nativa as referências ou a sintaxe do dialeto SQL diferem; a intenção do contrato e a forma de saída permanecem os mesmos.
Bloco Fonte de Bronze
Exatamente o mesmo bloco em Databricks, AWS, Snowflake, Fabric e GCP:
source:
type: rest_api
name: usgs_earthquake_2_5_day_geojson
system: usgs
request:
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
method: GET
headers:
Accept: application/geo+json, application/json
User-Agent: ContractForge real ingestion test
response:
mode: raw
raw_column: raw_response
limits:
timeout_seconds: 60
retry_attempts: 3
retry_backoff_seconds: 2
max_page_bytes: 10485760
max_total_bytes: 10485760
max_records: 1
Exatamente o mesmo ciclo de vida de bronze e bloco de qualidade em Databricks, AWS, Snowflake, Fabric e GCP:
layer: bronze
mode: overwrite
schema_policy: permissive
quality_rules:
required_columns: [raw_response, response_page_number]
not_null: [raw_response]
unique_key: [response_page_number]
Contrato de Evento Prata
Databricks, AWS, Fabric e GCP compartilham o mesmo formato de evento declarativo contrato. Snowflake expressa o mesmo contrato de saída que SQL nativo porque seu caminho de tempo de execução executa SQL diretamente.
layer: silver
mode: overwrite
schema_policy: additive_only
select_columns: [raw_response, response_page_number]
schemas:
usgs_geojson_feed: |
STRUCT<
type: STRING,
metadata: STRUCT<generated: BIGINT, url: STRING, title: STRING, status: BIGINT, api: STRING, count: BIGINT>,
bbox: ARRAY<DOUBLE>,
features: ARRAY<STRUCT<
type: STRING,
id: STRING,
properties: STRUCT<
mag: DOUBLE, place: STRING, time: BIGINT, updated: BIGINT, tz: BIGINT, url: STRING,
detail: STRING, felt: BIGINT, cdi: DOUBLE, mmi: DOUBLE, alert: STRING, status: STRING,
tsunami: BIGINT, sig: BIGINT, net: STRING, code: STRING, ids: STRING, sources: STRING,
types: STRING, nst: BIGINT, dmin: DOUBLE, rms: DOUBLE, gap: DOUBLE, magType: STRING,
type: STRING, title: STRING
>,
geometry: STRUCT<type: STRING, coordinates: ARRAY<DOUBLE>>
>>
>
transform:
shape:
parse_json:
- column: raw_response
alias: payload
schema_ref: usgs_geojson_feed
arrays:
- path: payload.features
mode: explode_outer
alias: feature
columns:
payload.metadata.generated: {alias: feed_generated_epoch_ms, cast: BIGINT}
payload.metadata.title: {alias: feed_title, cast: STRING}
payload.metadata.count: {alias: feed_event_count, cast: BIGINT}
payload.metadata.api: {alias: feed_api_version, cast: STRING}
payload.bbox: {alias: feed_bbox}
feature.id: {alias: earthquake_id, cast: STRING}
feature.type: {alias: geojson_feature_type, cast: STRING}
feature.properties.title: {alias: event_title, cast: STRING}
feature.properties.place: {alias: place, cast: STRING}
feature.properties.mag: {alias: magnitude, cast: DOUBLE}
feature.properties.magType: {alias: magnitude_type, cast: STRING}
feature.properties.time: {alias: event_epoch_ms, cast: BIGINT}
feature.properties.updated: {alias: updated_epoch_ms, cast: BIGINT}
feature.properties.status: {alias: event_status, cast: STRING}
feature.properties.type: {alias: event_type, cast: STRING}
feature.properties.alert: {alias: alert_level, cast: STRING}
feature.properties.tsunami: {alias: tsunami_flag, cast: INT}
feature.properties.sig: {alias: significance, cast: BIGINT}
feature.properties.net: {alias: network, cast: STRING}
feature.properties.code: {alias: network_event_code, cast: STRING}
feature.properties.url: {alias: event_url, cast: STRING}
feature.properties.detail: {alias: detail_url, cast: STRING}
feature.properties.felt: {alias: felt_reports, cast: BIGINT}
feature.properties.cdi: {alias: community_intensity, cast: DOUBLE}
feature.properties.mmi: {alias: instrumental_intensity, cast: DOUBLE}
feature.geometry.type: {alias: geometry_type, cast: STRING}
feature.geometry.coordinates: {alias: coordinates}
longitude: {alias: longitude, expression: "CAST(feature.geometry.coordinates[0] AS DOUBLE)"}
latitude: {alias: latitude, expression: "CAST(feature.geometry.coordinates[1] AS DOUBLE)"}
depth_km: {alias: depth_km, expression: "CAST(feature.geometry.coordinates[2] AS DOUBLE)"}
standardize:
event_status: {trim: true, lower: true, empty_as_null: true}
event_type: {trim: true, lower: true, empty_as_null: true}
magnitude_type: {trim: true, lower: true, empty_as_null: true}
alert_level: {trim: true, lower: true, empty_as_null: true}
network: {trim: true, lower: true}
derive:
event_time: CAST(from_unixtime(event_epoch_ms / 1000) AS TIMESTAMP)
updated_at: CAST(from_unixtime(updated_epoch_ms / 1000) AS TIMESTAMP)
feed_generated_at: CAST(from_unixtime(feed_generated_epoch_ms / 1000) AS TIMESTAMP)
event_date: to_date(CAST(from_unixtime(event_epoch_ms / 1000) AS TIMESTAMP))
magnitude_band: CASE WHEN magnitude IS NULL THEN 'unknown' WHEN magnitude < 3 THEN 'minor' WHEN magnitude < 5 THEN 'light' WHEN magnitude < 7 THEN 'strong' ELSE 'major' END
is_tsunami_related: tsunami_flag = 1
normalized_at_utc: CURRENT_TIMESTAMP()
deduplicate:
keys: [earthquake_id]
order_by:
- {column: updated_at, direction: desc, nulls: last}
- {column: feed_generated_at, direction: desc, nulls: last}
filter_expression: earthquake_id IS NOT NULL
Exatamente o mesmo bloco de qualidade de prata em Databricks, AWS, Snowflake, Fabric e GCP:
quality_rules:
not_null: [earthquake_id, event_time, latitude, longitude]
unique_key: [earthquake_id]
expressions:
- name: valid_geojson_point
expression: geometry_type = 'Point'
severity: warn
message: USGS summary feeds should expose point geometries.
- name: valid_coordinates
expression: latitude BETWEEN -90 AND 90 AND longitude BETWEEN -180 AND 180
severity: abort
message: Coordinates must be valid WGS84 latitude/longitude.
- name: reasonable_depth
expression: depth_km IS NULL OR depth_km BETWEEN -20 AND 800
severity: warn
message: Earthquake depth is outside the expected operational range.
- name: non_negative_magnitude
expression: magnitude IS NULL OR magnitude >= 0
severity: warn
message: Magnitude should not be negative for normal earthquake events.
Contrato Resumo Diário Ouro
Mesma forma de consulta normalizada em Databricks, AWS, Snowflake, Fabric e GCP. O
o identificador da tabela de origem difere de acordo com o adaptador; Snowflake usa IFF para o
boolean sum.
SELECT
event_date,
COUNT(*) AS earthquake_count,
SUM(CASE WHEN is_tsunami_related THEN 1 ELSE 0 END) AS tsunami_related_count,
AVG(magnitude) AS avg_magnitude,
MAX(magnitude) AS max_magnitude,
AVG(depth_km) AS avg_depth_km,
COUNT(DISTINCT network) AS reporting_networks,
MAX(updated_at) AS last_event_update_at,
CURRENT_TIMESTAMP() AS computed_at_utc
FROM <silver_events_table>
WHERE event_date IS NOT NULL
GROUP BY event_date
Exatamente o mesmo ciclo de vida de resumo diário e bloco de qualidade em Databricks, AWS, Snowflake, Fabric e GCP:
layer: gold
mode: overwrite
schema_policy: additive_only
quality_rules:
not_null: [event_date]
expressions:
- name: positive_daily_count
expression: earthquake_count > 0
severity: abort
message: Daily summary rows must represent at least one earthquake.
Contrato de Bandas de Magnitude de Ouro
Normalizado o mesmo corpo de consulta em Databricks, AWS, Snowflake, Fabric e GCP. Apenas o identificador da tabela de origem é alterado.
SELECT
magnitude_band,
event_type,
COUNT(*) AS event_count,
MIN(magnitude) AS min_magnitude,
AVG(magnitude) AS avg_magnitude,
MAX(magnitude) AS max_magnitude,
MIN(event_time) AS first_event_time,
MAX(event_time) AS latest_event_time,
CURRENT_TIMESTAMP() AS computed_at_utc
FROM <silver_events_table>
GROUP BY magnitude_band, event_type
Ciclo de vida de banda de magnitude e bloco de qualidade exatamente da mesma magnitude em Databricks, AWS, Snowflake, Fabric e GCP:
layer: gold
mode: overwrite
schema_policy: additive_only
quality_rules:
not_null: [magnitude_band]
expressions:
- name: positive_band_count
expression: event_count > 0
severity: abort
message: Magnitude-band summary rows must represent at least one event.
Anotações e operações
Os contratos de anotação e operação mantêm o mesmo conteúdo nos adaptadores. Por exemplo, o bloco de anotação de bronze é:
table:
description: Raw USGS Earthquake GeoJSON feed response.
tags:
domain: geospatial
provider: usgs
source_format: geojson
columns:
raw_response:
description: Raw GeoJSON FeatureCollection response body.
response_page_number:
description: REST connector page number.
O bloco de operações bronze também é idêntico em todos os adaptadores:
criticality: medium
expected_frequency: daily
freshness_sla_minutes: 1440
alert_on_failure: true
alert_on_quality_fail: true
runbook_url: https://example.com/runbooks/contractforge/usgs-earthquake-feed
ownership:
business_owner: platform-data
technical_owner: data-engineering
tags:
project: usgs-rest-medallion
layer: bronze
Diferenças de binding por adaptador
A comparação antes era tratada como diferença de parâmetros de contrato. Agora ela é organizada como binding de adaptador, porque a superfície reutilizável do contrato é maior que a superfície específica de plataforma.
Cada adaptador grava no seu namespace nativo de tabelas. O conector de origem, o formato bronze da resposta bruta, a ordem medalhão, as regras de qualidade, o modo de escrita e os resultados de negócio gold permanecem alinhados. As diferenças abaixo mostram apenas o binding nativo: onde cada adaptador armazena tabelas, como referencia a camada anterior e qual pré-requisito de plataforma é necessário para executar a mesma intenção.
rest_api + mesma URL USGS GeoJSONraw_response no bronze, mesmo modelo de eventos no silverUnity Catalog e Delta
A lógica do contrato é declarativa; o binding nativo é catálogo/esquema/tabela mais uma propriedade Delta.
- Destino bronze
workspace.cf_usgs_rest_bronze.b_usgs_earthquake_geojson- Destino silver
workspace.cf_usgs_rest_silver.s_usgs_earthquake_events- Destinos gold
workspace.cf_usgs_rest_gold.g_usgs_earthquake_daily_summaryworkspace.cf_usgs_rest_gold.g_usgs_earthquake_magnitude_bands- Hint nativo
delta.enableChangeDataFeed: "true"
Glue Catalog e Iceberg
A lógica do contrato é declarativa; o binding nativo adiciona referências Glue/Iceberg e um warehouse S3.
- Destino bronze
contractforge.cf_usgs_rest_bronze.b_usgs_earthquake_geojson- Entrada silver
glue_catalog.contractforge_cf_usgs_rest_bronze.b_usgs_earthquake_geojson- Destinos gold
contractforge.cf_usgs_rest_gold.g_usgs_earthquake_daily_summarycontractforge.cf_usgs_rest_gold.g_usgs_earthquake_magnitude_bands- Hint nativo
s3://.../warehouse/usgs-rest/
Esquema de banco de dados e SQL
A fonte REST é a mesma; o binding nativo adiciona objetos de banco de dados, SQL e acesso externo.
- Destino bronze
CONTRACTFORGE_TEST_DB.PUBLIC.CF_USGS_REST_BRONZE- Destino silver
CONTRACTFORGE_TEST_DB.PUBLIC.CF_USGS_REST_SILVER- Destinos gold
CONTRACTFORGE_TEST_DB.PUBLIC.CF_USGS_REST_GOLD_DAILYCONTRACTFORGE_TEST_DB.PUBLIC.CF_USGS_REST_GOLD_BANDS- Pré-requisito de runtime
CF_USGS_REST_ACCESS
Notebooks Lakehouse e Delta
A mesma intenção do medalhão é executada nos notebooks Fabric gerados com tabelas Lakehouse e evidências de tabela de controle.
- Destino bronze
cf_usgs_rest_bronze.b_usgs_earthquake_geojson- Destino silver
cf_usgs_rest_silver.s_usgs_earthquake_events- Destinos gold
cf_usgs_rest_gold.g_usgs_earthquake_daily_summarycf_usgs_rest_gold.g_usgs_earthquake_magnitude_bands- Pré-requisito de runtime
Fabric workspace + Lakehouse + execução de notebook
BigQuery e Workflows
A mesma origem e as mesmas saídas medalhão são executadas com tabelas BigQuery, SQL BigQuery e o runner certificado em Workflows.
- Destino bronze
contractforge_test.cf_usgs_rest_bronze.b_usgs_earthquake_geojson- Destino silver
contractforge_test.cf_usgs_rest_silver.s_usgs_earthquake_events- Destinos gold
contractforge_test.cf_usgs_rest_gold.g_usgs_earthquake_daily_summarycontractforge_test.cf_usgs_rest_gold.g_usgs_earthquake_magnitude_bands- Pré-requisito de runtime
BigQuery dataset + artefatos GCS + runner Workflows opcional
Registro de diferenças
| Tema | O que permanece igual | Diferença nativa |
|---|---|---|
| Fonte REST | Todos os adaptadores declaram source.type: rest_api, method: GET, o mesmo URL e a mesma coluna de resposta bruta. | A execução do procedimento hospedado Snowflake também precisa da integração de acesso externo CF_USGS_REST_ACCESS; Fabric e GCP vinculam-se por meio de suas superfícies de tempo de execução de propriedade do adaptador. |
| Vinculação de tabela | Cada contrato escreve camadas de bronze, prata e ouro com a mesma função lógica. | Os nomes de catálogo, esquema e tabela seguem o modelo de nomenclatura de cada plataforma. |
| Referências entre camadas | Silver lê bronze; gold lê silver. | As referências totalmente qualificadas diferem entre Unity Catalog, Glue Catalog/Iceberg, objetos de banco Snowflake, tabelas Fabric Lakehouse e datasets BigQuery. |
| Transformação silver | O formato do evento de saída, os filtros, os campos derivados e a regra de deduplicação são os mesmos. | Databricks, AWS, Fabric e GCP usam o caminho declarativo de transformação; Snowflake usa SQL nativo com PARSE_JSON, LATERAL FLATTEN e QUALIFY. |
| Hints de armazenamento | A configuração de armazenamento não altera a lógica de negócio nem a semântica de qualidade. | Databricks configura uma propriedade Delta; AWS configura um warehouse Iceberg; Fabric usa Lakehouse storage; GCP liga artefatos BigQuery/GCS; este contrato Snowflake não tem extensão de armazenamento. |
Trechos de parâmetros de contrato
Qualidade compartilhada e intenção de escrita:
mode: overwrite
schema_policy: additive_only
quality_rules:
not_null: [earthquake_id, event_time, latitude, longitude]
unique_key: [earthquake_id]
Databricks bronze binding:
source:
type: rest_api
request:
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
target:
catalog: workspace
schema: cf_usgs_rest_bronze
table: b_usgs_earthquake_geojson
AWS bronze binding:
source:
type: rest_api
request:
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
target:
catalog: contractforge
schema: cf_usgs_rest_bronze
table: b_usgs_earthquake_geojson
Snowflake bronze binding:
source:
type: rest_api
request:
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
target:
catalog: CONTRACTFORGE_TEST_DB
schema: PUBLIC
table: CF_USGS_REST_BRONZE
Fabric bronze binding:
source:
type: rest_api
request:
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
target:
schema: cf_usgs_rest_bronze
table: b_usgs_earthquake_geojson
extensions:
fabric:
lakehouse: contractforge_test_lakehouse
GCP bronze binding:
source:
type: rest_api
request:
method: GET
url: https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson
target:
catalog: contractforge-test
schema: cf_usgs_rest_bronze
table: b_usgs_earthquake_geojson
extensions:
gcp:
location: US