Este documento aborda o problema de SchemaError encontrado ao processar arquivos JSONL.gz com a biblioteca Polars, apresentando soluções detalhadas.
- Manifestação do Problema
Ao utilizar pl.read_ndjson() (ou scan_ndjson) para ler arquivos .jsonl.gz, ocorre o seguinte erro:
polars.exceptions.SchemaError: incompatibilidade de tipo de dados para a coluna fórmula: entrada: Boolean != alvo: Null
Comportamento Inesperado: Quando os dados são carregados manualmente usando as bibliotecas gzip e json antes de converter para pl.DataFrame, a operação é bem-sucedida.
- Causa Fundamental: Limitações do Mecanismo de Inferência
- Amostragem Inadequada: Polars examina as primeiras \(N\) linhas do arquivo (padrão: 100) para determinar automaticamente o tipo de cada coluna.
- Fixação de Tipo Null: Se nas primeiras \(N\) linhas todos os valores da coluna
fórmulaforemnull(equivalente aNoneem Python), Polars define o tipo dessa coluna comopl.Null. - Conflito de Tipos: Quando nas linhas subsequentes (a partir da \(N+1\)) aparecem valores
TrueouFalse(tipoBoolean), o interpretaodr não consegue inserir esses valores booleanos em um slot que foi definido como "sempre vazio", resultando em falha. - Impacto de Estruturas Aninhadas: Se essa chave estiver dentro de uma
Struct(dicionário), o conflito é propagado camada por camada, causando falha na análise de toda a colunametadados.
- Soluções Propostas
Solução A: Definir Explicitamente o Schema Aninhado (Mais Rigoroso e Performático)
Forneça a estrutura da coluna e seus subcampos através do parâmetro schema_overrides. Isso evita a amostragem e faz com que o Polars leia os dados conforme o tipo definido.
Exemplo de Código:
Python
import polars as pl
# 1. Definir a estrutura aninhada em camadas
campos_sub_l1 = [
pl.Field("gatilho", pl.Boolean),
pl.Field("probabilidade_rotulo", pl.Float64)
]
# 2. Construir a estrutura complexa de metadados
schema_metadados = pl.Struct([
pl.Field("arquivo_origem", pl.String),
pl.Field("id_no_arquivo", pl.Int64),
pl.Field("fórmula", pl.Boolean), # Chave: forçar Boolean para resolver conflito
pl.Field("l1_fasttext", pl.Struct([
pl.Field("L1_CienciaBasica", pl.Struct(campos_sub_l1)),
pl.Field("L1_Engles", pl.Struct(campos_sub_l1)),
# ... outros subcampos
])),
# ... outros campos
])
# 3. Ler com substituição do schema inferido
df = pl.read_ndjson(
"dados.jsonl.gz",
schema_overrides={"metadados": schema_metadados}
)
Solução B: Ler como String e Decodificar Assincronamente (Mais Flexível)
Se você não deseja manter manualmente listas complexas de Field, pode ler todo o objeto como uma string JSON e depois usar o json_decode do Polars para análise dinâmica.
Exemplo de Código:
Python
df = pl.read_ndjson(
"dados.jsonl.gz",
schema_overrides={"metadados": pl.String} # Forçar leitura como string bruta
)
# Decodificar automaticamente a string JSON, geralmente mais inteligente que a amostragem inicial
df = df.with_columns(
pl.col("metadados").str.json_decode()
)
Solução C: Aumentar a Profundidade da Amostragem (Solução Temporária)
Se a coluna fórmula apenas ocasionalmente estiver ausente nas primeiras linhas, tente aumentar o número de linhas para inferência.
Python
df = pl.read_ndjson("dados.jsonl.gz", infer_schema_length=10000)
Nota: Se a distribuição dos dados for muito desigual, este método ainda pode falhar.
- Resumo de Conceitos Chave
- Relação de Inclusão de Tipos no Polars:
pl.Booleané "nulável", podendo conterTrue,Falseenull. Por outro lado,pl.Nullsó pode conternull. - Princípio de Substituição de Struct: Ao usar
schema_overridespara substtiuir campos internos de umaStruct, é necessário fornecer a definição completa dos campos daStruct, caso contrário, os campos não mencionados serão descartados. - Desafio no Modo Lazy: Ao usar
scan_ndjson(modo Lazy), o Polars exige alta precisão no Schema, pois o otimizador de consultas precisa saber previamente o tipo exato de cada coluna. - Recomendações de Implementação
- Se o Schema for fixo: Utilize a Solução A, que resolve o erro e oferece a maior velocidade de leitura.
- Se o Schema mudar frequentemente ou tiver muitos campos: Use a Solução B, que apresenta o menor custo de desenvolvimento.