Normalize a estrutura antes da qualidade e escreva.
Os conectores recuperam dados. As transformações tornam o DataFrame físico utilizável antes da execução das regras de qualidade e dos modos de gravação. Use este namespace para mutações que alteram linhas, colunas ou valores. Mantenha descrições de catálogo, PII, aliases e propriedade empresarial em contratos de governança divididos.
O namespace canônico
Use transform para preparação física do DataFrame. O atalho de nível superior shape permanece compatível com notebooks simples, mas novos contratos devem usar o namespace canônico.
A ordem de execução é determinística:
select_columnscolumn_mappingtransform.shapetransform.casttransform.standardizetransform.derivefilter_expressioncustom_keyswatermark_columnstransform.deduplicate- codificação de colunas de limpeza e controle
transform:
shape:
parse_json:
- column: raw_response
alias: payload
schema: "STRUCT<events:ARRAY<STRUCT<id:STRING,title:STRING>>>"
arrays:
- path: payload.events
mode: explode_outer
alias: event
columns:
event.id:
alias: event_id
cast: STRING
event.title:
alias: event_title
cast: STRING
cast:
event_id: string
standardize:
event_title:
trim: true
normalize_whitespace: true
derive:
event_date: to_date(ingestion_ts_utc)
deduplicate:
keys: [event_id]
order_by:
- column: ingestion_ts_utc
direction: desc
nulls: last
Princípios de design
Esquema explícito
A análise de JSON requer Spark DDL. Evite confiar na inferência de runtime para contratos importantes.
Cardinalidade é intencional
As operações de explosão alteram as contagens de linhas. Bronze bloqueia alterações inseguras de cardinalidade, a menos que seja explicitamente permitido.
Colunas são projeções
Quando columns é declarado, apenas os aliases declarados permanecem como colunas de negócios.
Conectores permanecem neutros
A estruturação de negócios pertence às transformações, não às soluções alternativas específicas do conector.
Os metadados ficam fora da transformação
Se um campo descreve significado, propriedade, PII, classificação ou capacidade de descoberta do catálogo, ele pertence a annotations ou operations, não a transform.
Onde o esquema pertence
ContractForge usa declarações de esquema em dois locais diferentes. Eles não devem ser tratados como campos intercambiáveis.
| Localização | Propósito | Use-o para | Não use para |
|---|---|---|---|
source.read.schema | Esquema de linha de origem física usado enquanto um conector ou leitor Spark materializa dados. | CSV, JSON, XML, Avro, pastas de arquivos e REST response.mode: records onde a inferência seria frágil. | Business JSON dentro de uma coluna de string já lida. |
schemas de nível superior com shape.parse_json.schema_ref | Spark DDL reutilizável para analisar uma string JSON depois que um DataFrame já existir. | Corpo do Event Hubs, resposta bruta REST, colunas de carga útil de texto e formatos de envelope. | Configurando como o Spark lê os arquivos de origem originais ou registros do conector. |
annotations | Metadados de catálogo e governança. | Descrições, aliases, tags, PII, confidencialidade e contexto de produto de dados. | Qualquer comportamento de transformação, lançamento, explosão ou análise. |
Regra prática
Se o Spark precisar do esquema para ler a fonte, coloque-o em source.read.schema. Se ContractForge já tiver uma coluna de string e precisar analisar seu conteúdo JSON, coloque o DDL em schemas de nível superior e referencie-o em transform.shape.parse_json.
Referência de campo de transformação
| Campo | Tipo | Obrigatório | Comportamento |
|---|---|---|---|
shape | objeto | Não | Analisa strings JSON, nivela estruturas, manipula matrizes e projeta colunas aninhadas. |
cast | string do mapa -> string | Não | Converte colunas existentes em tipos Spark SQL, como string, double, timestamp ou decimal(18,2). |
standardize | string do mapa -> objeto | Não | Aplica limpeza de cadeia determinística às colunas declaradas. |
standardize.<column>.trim | booleano | Não | Apara espaços em branco à esquerda e à direita. |
standardize.<column>.lower | booleano | Não | Converte o texto em minúsculas. Não pode ser combinado com upper. |
standardize.<column>.upper | booleano | Não | Converte texto em maiúsculas. Não pode ser combinado com lower. |
standardize.<column>.normalize_whitespace | booleano | Não | Substitui espaços em branco repetidos por um único espaço. |
standardize.<column>.empty_as_null | booleano | Não | Converte a string vazia final em nula. |
derive | string do mapa -> string | Não | Cria ou substitui colunas usando expressões Spark SQL. |
deduplicate.keys | string ou lista | Sim, quando deduplicate existe | Colunas-chave usadas para manter uma linha por chave. |
deduplicate.order_by | string ou lista | Sim, quando deduplicate existe | Ordenação determinística. Prefira o formulário de lista estruturada para novos contratos. |
deduplicate.order_by[].column | string | Sim para itens de pedidos estruturados | Coluna usada para ordenação. |
deduplicate.order_by[].direction | asc ou desc | Não | Ordenar direção. O padrão é desc. |
deduplicate.order_by[].nulls | first ou last | Não | Cláusula de ordenação nula. |
Elenco, padronização e derivação
Use essas operações quando a origem já for tabular o suficiente e o contrato de destino precisar de preparação explícita de valor sem código de notebook personalizado.
- YAML
- Python
transform:
cast:
order_id: string
amount: decimal(18,2)
updated_at: timestamp
standardize:
customer_email:
trim: true
lower: true
empty_as_null: true
status:
trim: true
upper: true
normalize_whitespace: true
derive:
order_date: to_date(updated_at)
net_amount: amount - coalesce(discount_amount, 0)
from contractforge import ingest
result = ingest(
source=df,
target_table="orders",
catalog="main",
layer="silver",
mode="append",
transform={
"cast": {
"order_id": "string",
"amount": "decimal(18,2)",
"updated_at": "timestamp",
},
"standardize": {
"customer_email": {
"trim": True,
"lower": True,
"empty_as_null": True,
},
"status": {
"trim": True,
"upper": True,
"normalize_whitespace": True,
},
},
"derive": {
"order_date": "to_date(updated_at)",
"net_amount": "amount - coalesce(discount_amount, 0)",
},
},
)
Use cast para preparação do tipo de destino, standardize para limpeza simples de string e derive para expressões Spark SQL que criam colunas. Se a expressão se tornar uma grande lógica de negócios, promova-a para uma visão revisada, etapa de notebook ou modelo downstream.
Referência de campo de forma
O contrato shape é executado após o conector de origem e antes das regras de qualidade e modos de gravação. Destina-se à normalização física de registros aninhados ou semiestruturados, não à agregação de negócios.
| Campo | Tipo | Obrigatório | Comportamento |
|---|---|---|---|
parse_json | lista | Não | Analisa colunas de string declaradas com um esquema Spark DDL explícito usando from_json. |
parse_json[].column | string | Sim | Coluna de cadeia de caracteres de origem ou caminho de cadeia de caracteres aninhada a ser analisado. |
parse_json[].schema | string | Sim | Esquema DDL do Spark. Use STRUCT<...>, ARRAY<...> ou qualquer tipo de dados Spark válido aceito por from_json. |
parse_json[].alias | string | Não | Coluna de saída. Obrigatório ao analisar um caminho aninhado. Deve ser um nome simples de coluna de nível superior. |
parse_json[].drop_source | booleano | Não | Descarta a coluna de origem original após a análise. Compatível apenas com colunas de origem de nível superior. |
flatten.enabled | booleano | Não | Achata campos struct em colunas de nível superior. |
flatten.separator | string | Não | Separador usado em nomes de colunas geradas. O comportamento padrão segue o padrão de implementação. |
flatten.max_depth | inteiro | Não | Profundidade máxima de aninhamento de estrutura para nivelar. |
flatten.include | lista | Não | Colunas estruturais de nível superior para nivelar. Outras colunas são mantidas como estão. |
flatten.exclude | lista | Não | Caminhos a serem excluídos do nivelamento. |
zip_arrays | lista | Não | Combina matrizes paralelas em uma matriz de estruturas antes de explodir. |
zip_arrays[].alias | string | Sim | Coluna da matriz de saída contendo estruturas. |
zip_arrays[].columns | mapa | Sim | Mapa do caminho da matriz de origem para o nome do campo struct de saída. Requer pelo menos duas matrizes. |
arrays | lista | Não | Transforma arrays mantendo, serializando, dimensionando, pegando o primeiro elemento ou explodindo. |
arrays[].path | string | Sim | Caminho da matriz. Use notação de ponto; não use a sintaxe []. |
arrays[].mode | enumeração | Não | keep, to_json, size, first, explode ou explode_outer. |
arrays[].alias | string | Não | Coluna de saída. Obrigatório implicitamente para modos de alteração de cardinalidade quando nenhum alias padrão é desejado. |
arrays[].allow_cartesian | booleano | Não | Permite múltiplas explosões de irmãos que podem multiplicar linhas. O padrão protege contra expansão cartesiana acidental. |
columns | mapa | Não | Projeção final. Quando declarado, apenas as colunas projetadas são mantidas. |
columns.<path>.alias | string | Não | Coluna de saída. O padrão é o caminho com pontos substituídos por sublinhados quando nenhuma expressão é usada. |
columns.<path>.cast | string | Não | Tipo Spark SQL usado para converter a expressão projetada. |
columns.<path>.expression | string | Não | Expressão SQL do Spark. Requer um alias explícito. |
allow_cardinality_change_on_bronze | booleano | Não | Permite explode/explode_outer em contratos bronze quando o contrato altera intencionalmente a cardinalidade da linha. |
Matrizes paralelas
Use zip_arrays antes de explodir quando uma API retornar vários arrays que representam observações alinhadas.
transform:
shape:
zip_arrays:
- alias: hourly_observation
columns:
payload.hourly.time: time
payload.hourly.temperature_2m: temperature
payload.hourly.relative_humidity_2m: humidity
arrays:
- path: hourly_observation
mode: explode_outer
alias: observation
Padrões de exemplo
NASA EONETE
JSON REST bruto para linhas
O conector REST captura JSON bruto, parse_json aplica um esquema DDL explícito e a explosão de matriz transforma eventos em registros prateados.
Open-Meteo
Matrizes paralelas
As respostas meteorológicas por hora retornam matrizes alinhadas. zip_arrays preserva o significado posicional antes de explodir.
Terremotos USGS
Estruturas e coordenadas aninhadas
Campos estruturais e índices de array podem ser projetados de forma declarativa, mantendo os notebooks livres do encanamento de colunas do Spark.
Arquivos blob/S3
Esquema primeiro
Esquemas de arquivos explícitos mais transform.deduplicate tornam os exemplos de armazenamento de objetos determinísticos e revisáveis.
Desduplicação determinística
Use transform.deduplicate quando um lote puder conter vários registros para a mesma chave comercial e o contrato tiver uma regra de pedido clara.
- YAML
- Python
transform:
deduplicate:
keys: [order_id]
order_by:
- column: updated_at
direction: desc
nulls: last
- column: sequence
direction: desc
transform = {
"deduplicate": {
"keys": ["order_id"],
"order_by": [
{"column": "updated_at", "direction": "desc", "nulls": "last"},
{"column": "sequence", "direction": "desc"},
],
}
}
Para contratos existentes, fragmentos SQL como updated_at DESC NULLS LAST ainda são aceitos. Para novos contratos, prefira a lista estruturada porque é mais fácil de validar e revisar.
Mapeamento de coluna versus forma
Use column_mapping para renomeações simples de origem para destino antes de colunas técnicas serem adicionadas. Use transform.shape.columns quando a projeção de destino precisar de conversões, caminhos aninhados, expressões, índices de array ou uma reescrita estrutural completa.
column_mapping:
id: customer_id
ingestion_date: source_ingestion_date
transform:
shape:
columns:
properties.mag:
alias: magnitude
cast: DOUBLE
geometry.coordinates[0]:
alias: longitude
cast: DOUBLE
Matrizes aninhadas em qualquer ordem
Para matrizes aninhadas, declare o pai explodido e, em seguida, faça referência ao alias gerado nas operações filho. ContractForge resolve caminhos de array pendentes iterativamente, para que o contrato possa expressar a hierarquia pretendida sem código Spark personalizado.
transform:
shape:
arrays:
- path: payload.orders
mode: explode_outer
alias: order
- path: order.items
mode: explode_outer
alias: item
columns:
order.id:
alias: order_id
cast: STRING
item.sku:
alias: sku
cast: STRING
item.quantity:
alias: quantity
cast: INT
Regra de cardinalidade
Duas explosões de irmãos sob o mesmo pai são bloqueadas, a menos que allow_cartesian seja verdadeiro. As explosões pai-filho são válidas porque cada etapa tem um caminho de expansão de linha claro.
Guarda-corpos
- A análise JSON requer um esquema Spark DDL declarado; isso evita desvios acidentais de inferência.
- A alteração da cardinalidade no Bronze é bloqueada por padrão porque as camadas brutas normalmente devem preservar os registros de origem.
- Matrizes irmãs não são explodidas independentemente, a menos que o contrato evite produtos cartesianos acidentais.
- A ordem de desduplicação deve ser determinística para os modos de mesclagem e diferença de hash.
lowereuppernão podem ser habilitados juntos para a mesma coluna padronizada.cast,standardizeededuplicate.keysexigem que existam colunas depois deshapee antes da gravação.