Pular para o conteúdo
SparquetSparquet

Conectores

Um conector é escolhido pelo campo format de um input, de um output ou de uma origem de join/union. O mesmo registry serve aos três, e é extensível — veja Adicionando o seu.

Formato Leitura Escrita Notas
parquet ✓ ✓ Nativo do Spark
delta ✓ ✓ Upserts com MERGE, time travel
iceberg ✓ ✓ MERGE INTO
csv ✓ ✓ header e inferSchema com default true; aspas RFC 4180
txt ✓ ✓ texto plano, coluna única value
view ✓ ✓ Spark temp views, auto-cache
kafka ✓ ✓ leitura e publicação batch; Amazon MSK
postgresql ✓ ✓ JDBC
mysql ✓ ✓ JDBC
mariadb ✓ ✓ JDBC
sqlserver ✓ ✓ JDBC
oracle ✓ ✓ JDBC (service name)
bigquery ✓ ✓ Google BigQuery
snowflake ✓ ✓ Snowflake
redshift ✓ ✓ Amazon Redshift, staging em S3
mongodb ✓ ✓ MongoDB
documentdb ✓ ✓ Amazon DocumentDB (protocolo Mongo)
dynamodb ✓ ✓ Amazon DynamoDB, escrita é upsert
cassandra ✓ ✓ Cassandra / ScyllaDB, escrita é upsert
elasticsearch ✓ ✓ Elasticsearch / OpenSearch
{ "format": "parquet", "path": "/data/curated/orders", "mode": "overwrite", "partition_by": ["country"] }

Qualquer opção Parquet do Spark passa por options. path é um diretório de arquivos part, não um único arquivo.

{ "format": "csv", "path": "/data/landing/orders", "options": { "sep": ";", "encoding": "UTF-8" } }

Defaults aplicados pelo framework: header: true e inferSchema: true na leitura, header: true na escrita, encoding: UTF-8 e escape: " em ambas. inferSchema custa uma passada extra sobre os dados — defina um cast explícito e desligue-o para feeds grandes e estáveis.

As aspas seguem o RFC 4180: uma aspa dentro de um campo é escrita dobrada (""), não escapada com barra invertida (\") como o Spark faz por default. O Spark relê o dialeto dele, mas o csv do Python, o pandas e o Excel não — era isso que quebrava o validations.report, cuja coluna rule_params é um JSON cheio de aspas, justamente nas ferramentas em que ele é analisado. Para ler um arquivo gravado no dialeto antigo, declare: "options": { "escape": "\\" }.

// lê uma tabela, ou um path, ou uma versão passada
{ "format": "delta", "path": "catalog.schema.orders" }
{ "format": "delta", "path": "/mnt/raw/orders", "options": { "versionAsOf": "5" } }
{ "format": "delta", "path": "catalog.schema.orders", "options": { "timestampAsOf": "2026-01-01T00:00:00Z" } }
// upsert
{ "format": "delta", "path": "catalog.schema.orders", "mode": "merge",
"options": { "merge_keys": ["order_id"], "merge_condition": "T.deleted = false" } }

path é tratado como nome de tabela quando contém um ponto e não começa com / ou um storage scheme; caso contrário, como um path. Em merge_condition, T é a tabela alvo e S o DataFrame de entrada.

Fora do Databricks, instale o pacote OSS: pip install "sparquet[delta]".

{ "format": "iceberg", "path": "catalog.db.orders", "mode": "merge", "options": { "merge_keys": ["id"] } }
{ "format": "txt", "path": "/data/exports/lines", "mode": "overwrite" }

Lê para uma única coluna value, e escreve um DataFrame que precisa ter exatamente uma coluna string — projete-a antes com select.

{ "format": "view", "path": "orders_staging", "mode": "overwrite" }

Registra uma Spark temp view, cacheada por padrão, para que um pipeline posterior na mesma sessão possa lê-la como {"format": "view", "path": "orders_staging"}. Este é o mecanismo de staging por trás dos jobs multi-pipeline — um escreve a view, o próximo a consome.

options.scope escolhe o tempo de vida: session (default) é uma temp view normal, visível apenas à sessão atual; global usa createOrReplaceGlobalTempView, visível a todas as sessões da mesma aplicação Spark (leia-a como global_temp.<name>, ou com scope: "global" no reader).

Leitura batch e publicação batch. path é o tópico. Requer spark-sql-kafka-0-10 no classpath.

// lê o tópico inteiro
{
"format": "kafka",
"path": "orders-events",
"options": { "bootstrap_servers": "broker1:9092,broker2:9092", "startingOffsets": "earliest" }
}
// publica
{
"format": "kafka",
"path": "orders-events",
"mode": "append",
"transformations": [
{ "type": "with_column", "column": "value", "expression": "to_json(payload)" }
],
"options": {
"bootstrap_servers": "broker1:9092,broker2:9092",
"value_column": "value",
"key_column": "order_id"
}
}

Na leitura, o DataFrame volta com o schema nativo do Kafka (binário key/value, topic, partition, offset, timestamp, timestampType) — geralmente seguido de um CAST(value AS STRING). Os defaults de batch são startingOffsets: earliest e endingOffsets: latest, então uma execução lê o tópico inteiro; sobrescreva-os, ou passe assign / subscribePattern no lugar do default subscribe.

Na escrita, a value_column configurada (default payload) e a key_column (default header, null para omitir) são renomeadas para value e key, e toda coluna fora de {key, value, topic, partition, timestamp, headers} é descartada antes da escrita.

bootstrap_servers é um alias amigável para kafka.bootstrap.servers. Para o Amazon MSK com auth IAM, passe kafka.security.protocol=SASL_SSL e kafka.sasl.mechanism=AWS_MSK_IAM em options (além do JAR aws-msk-iam-auth no classpath).

Nativo, sem JAR extra. path é um diretório; o default é um objeto por linha (JSON Lines). Defina multiLine: "true" para ler um documento por arquivo.

{ "format": "json", "path": "/data/landing/events", "options": { "multiLine": "true" } }

Formato colunar nativo (como o Parquet), sem JAR extra. As opções incluem compression (default zlib) e mergeSchema.

{ "format": "orc", "path": "/data/curated/orders", "mode": "overwrite", "partition_by": ["dt_ref"] }

Orientado a linhas; requer o pacote org.apache.spark:spark-avro no classpath. Opções: avroSchema, compression (snappy/deflate/bzip2/xz), recordName.

{ "format": "avro", "path": "/data/raw/events" }

Requer o pacote com.databricks:spark-xml (registra o formato xml). rowTag é obrigatório na leitura e escrita; rootTag (default rows) nomeia a raiz da escrita.

{ "format": "xml", "path": "/data/raw/catalog", "options": { "rowTag": "book" } }

Somente leitura (binaryFile). Carrega arquivos inteiros nas colunas path, modificationTime, length, content (binário) — imagens, PDFs, blobs. Não há writer binário; persista content via parquet/delta.

{ "format": "binary", "path": "/data/raw/docs", "options": { "pathGlobFilter": "*.pdf" } }

Formato de tabela lakehouse com upserts. Requer o JAR hudi-spark-bundle e as session extensions do Hudi. path é o base path da tabela; particionamento e upsert são dirigidos por opções hoodie.* (o partition_by do framework não é usado).

{
"format": "hudi",
"path": "s3a://lake/hudi/orders",
"mode": "append",
"options": {
"hoodie.table.name": "orders",
"hoodie.datasource.write.recordkey.field": "order_id",
"hoodie.datasource.write.precombine.field": "updated_at",
"hoodie.datasource.write.operation": "upsert"
}
}

postgresql, mysql, mariadb, sqlserver e oracle compartilham uma base JDBC única com dialetos por banco que preenchem a classe do driver, a porta default e o formato da URL. path é o nome da tabela (dbtable).

// lê uma tabela
{
"format": "postgresql",
"path": "public.orders",
"options": {
"host": "db.internal", "port": 5432, "database": "sales",
"user": "reader", "password": "…"
}
}
// ou informe a URL completa e uma query com pushdown
{
"format": "sqlserver",
"path": "dbo.orders",
"options": {
"url": "jdbc:sqlserver://db:1433;databaseName=sales",
"query": "SELECT id, total FROM dbo.orders WHERE total > 0",
"user": "reader", "password": "…"
}
}

Opções de conexão: url (URL JDBC completa, tem precedência) ou host + database (+ port opcional, com default por banco) para montá-la; driver (com default por banco); user / password. As leituras também aceitam query (um SELECT usado no lugar de dbtable), dbtable (sobrescreve path), partitionColumn / lowerBound / upperBound / numPartitions para leituras paralelas, e fetchsize. As escritas suportam append e overwrite (truncate: "true" faz um TRUNCATE em vez de DROP/CREATE), além de batchsize, isolationLevel, createTableColumnTypes / createTableOptions. JDBC não tem merge — use append/overwrite.

O Spark pode entregar partes da consulta ao banco em vez de arrastar linhas pela rede para filtrá-las na JVM. As cinco alavancas têm default true no caminho de leitura do Spark 4 e são repassadas diretamente:

Opção O que vai para o banco
pushDownPredicate a cláusula WHERE
pushDownAggregate sum/count/min/max/avg e o GROUP BY
pushDownLimit o LIMIT
pushDownOffset o OFFSET
pushDownTableSample TABLESAMPLE
{ "format": "postgresql", "path": "public.orders",
"options": { "host": "db.internal", "database": "shop",
"pushDownAggregate": "true", "pushDownLimit": "true" } }

A restrição que importa: elas só se aplicam quando a leitura é de uma tabela. Com query o SELECT que você escreveu já é o corte, então o Spark o embrulha como subconsulta e não empurra nada mais para dentro dele. O pushdown de agregação também exige que a agregação seja a única coisa acima do scan — um filter sobre coluna calculada, um join ou uma UDF no meio e o banco recebe um SELECT simples. Ligar uma alavanca é um pedido, não um fato: { "type": "debug", "actions": ["pushdown"] } diz o que o plano de fato empurrou. Veja debug.

O mariadb monta uma URL jdbc:mysql:// com o driver do MySQL, de propósito. O Spark 4.1 não tem dialeto MariaDB e seu MySQLDialect só casa com URLs que começam por jdbc:mysql; com jdbc:mariadb:// o conector cai no dialeto default, que cita identificadores com " — e a MariaDB rejeita isso tanto na leitura quanto na escrita, já que o SELECT que o Spark monta cita as colunas do mesmo jeito:

You have an error in your SQL syntax ... near '"id" INTEGER'

A MariaDB fala o protocolo do MySQL, então o Connector/J alcança um servidor MariaDB e traz o dialeto com ele: citação com backtick, mapeamento de tipos do MySQL e SQL correto no pushdown de agregação e de LIMIT. Para usar o driver da MariaDB de todo modo, passe url e driver explicitamente junto com sessionVariables:

{ "format": "mariadb", "path": "orders",
"options": { "url": "jdbc:mariadb://db.internal:3306/shop?sessionVariables=sql_mode='ANSI_QUOTES'",
"driver": "org.mariadb.jdbc.Driver", "user": "app", "password": "..." } }

O preço é que "..." deixa de ser literal de string naquela sessão, o que importa para quem usa query. Uma URL jdbc:mariadb:// explícita sem ANSI_QUOTES emite aviso.

Para o Oracle, database é o service name (jdbc:oracle:thin:@//host:port/service).

path é project.dataset.table (ou dataset.table com um projeto default). Usa o spark-bigquery-connector.

{ "format": "bigquery", "path": "my-proj.sales.orders",
"options": { "parentProject": "billing-proj", "credentialsFile": "/secrets/sa.json" } }

Opções de leitura: query (requer viewsEnabled: "true"), parentProject (billing), credentialsFile / credentials, filter, maxParallelism. Escrita (overwrite / append): temporaryGcsBucket (staging indireto, default), writeMethod (indirect ou direct), partitionField / partitionType / clusteredFields.

path é a tabela (dbtable). Usa spark-snowflake + snowflake-jdbc.

{ "format": "snowflake", "path": "ANALYTICS.PUBLIC.ORDERS",
"options": {
"sfUrl": "myorg-acct.snowflakecomputing.com",
"sfUser": "loader", "sfPassword": "…",
"sfDatabase": "ANALYTICS", "sfSchema": "PUBLIC", "sfWarehouse": "LOAD_WH"
} }

A conexão é a família sfXxx (sfUrl, sfUser / sfPassword ou pem_private_key, sfDatabase, sfSchema, sfWarehouse, sfRole). As leituras aceitam query; as escritas suportam overwrite / append.

path é a tabela (dbtable). Usa o conector community spark-redshift, que faz staging via S3.

{ "format": "redshift", "path": "public.orders",
"options": {
"url": "jdbc:redshift://cluster:5439/sales",
"tempdir": "s3://my-bucket/redshift-staging/",
"aws_iam_role": "arn:aws:iam::…:role/redshift-copy"
} }

url e tempdir (um prefixo S3) são obrigatórios. A auth é user / password ou aws_iam_role; forward_spark_s3_credentials: "true" reutiliza as credenciais S3 da sessão. As escritas suportam overwrite / append e diststyle / distkey / sortkeyspec / tempformat.

path é a coleção. O mesmo Mongo Spark Connector serve o Amazon DocumentDB — aponte connection.uri para o cluster DocumentDB com ?tls=true&retryWrites=false.

{ "format": "mongodb", "path": "orders",
"options": { "connection.uri": "mongodb://user:pass@host:27017/", "database": "sales" } }

Opções: connection.uri (obrigatório), database, collection (sobrescreve path), aggregation.pipeline (pushdown de leitura). As escritas suportam overwrite / append, além de operationType (insert / replace / update), idFieldList, ordered.

path é a tabela (tableName). Usa spark-dynamodb.

{ "format": "dynamodb", "path": "orders", "options": { "region": "us-east-1" } }

Opções: region, roleArn, endpoint (ex.: DynamoDB local), throughput / targetCapacity, readPartitions / stronglyConsistentReads. As escritas são sempre um PutItem por linha — um upsert por chave primária (append); o DynamoDB não tem overwrite de tabela.

path é keyspace.table (ou apenas a tabela, com keyspace em options). Usa o spark-cassandra-connector.

{ "format": "cassandra", "path": "sales.orders",
"options": { "spark.cassandra.connection.host": "node1,node2" } }

Opções: keyspace / table (sobrescrevem path), spark.cassandra.connection.host / .port, spark.cassandra.auth.username / .password. As escritas são append (INSERT/upsert por chave); a tabela já deve existir.

path é o índice (resource). Usa o conector elasticsearch-hadoop — prefixo de opção es.*.

{ "format": "elasticsearch", "path": "orders",
"options": { "es.nodes": "es.internal", "es.port": "9200" } }

Opções: es.nodes / es.port, es.net.http.auth.user / .pass, es.nodes.wan.only (cloud/proxy), es.query (DSL de leitura), es.mapping.id (usa uma coluna como _id), es.write.operation (index / create / update / upsert). As escritas suportam append / overwrite.

Um formato separado com seu próprio conector (opensearch-hadoop) — prefixo de opção opensearch.*, não es.*. No mais, mesmo formato do Elasticsearch.

{ "format": "opensearch", "path": "orders",
"options": { "opensearch.nodes": "os.internal", "opensearch.port": "9200" } }

As opções espelham as do ES com o prefixo opensearch.: opensearch.nodes / opensearch.port, opensearch.net.http.auth.user / .pass, opensearch.nodes.wan.only, opensearch.query, opensearch.mapping.id, opensearch.write.operation.

No Spark 4 o conector é org.opensearch.client:opensearch-spark-40_2.13:2.0.0; no Spark 3.x é o opensearch-spark-30_2.12. Este também é o caminho suportado para um servidor Elasticsearch — veja o aviso acima.

Cada conector acima é distribuído como um pacote Spark que precisa estar no classpath. Declare-o por pipeline para que o job carregue sua própria dependência:

{
"spark": {
"configs": {
"spark.jars.packages": "org.postgresql:postgresql:42.7.3,org.apache.spark:spark-sql-kafka-0-10_2.12:3.5.1"
}
}
}

Numa plataforma gerenciada você também pode adicionar o pacote às bibliotecas do cluster. O framework nunca empacota esses drivers — um JAR ausente aparece como um ClassNotFoundException / Failed to find data source no momento da leitura ou escrita.

Registre um reader ou writer uma vez e todo pipeline no processo pode usá-lo:

fw.register_reader("my_format", MyReader) # class MyReader(BaseReader)
fw.register_writer("my_format", MyWriter) # class MyWriter(BaseWriter)

Veja Estendendo. O Studio preserva formatos desconhecidos ao longo da importação e exportação, então um conector customizado não quebra o canvas.