Erros de Correspondência de Schema ao Ler JSONL.gz com Polars

Este documento aborda o problema de SchemaError encontrado ao processar arquivos JSONL.gz com a biblioteca Polars, apresentando soluções detalhadas.

  1. 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.

  1. 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órmula forem null (equivalente a None em Python), Polars define o tipo dessa coluna como pl.Null.
  • Conflito de Tipos: Quando nas linhas subsequentes (a partir da \(N+1\)) aparecem valores True ou False (tipo Boolean), 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 coluna metadados.
  1. 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.

  1. Resumo de Conceitos Chave

  1. Relação de Inclusão de Tipos no Polars: pl.Boolean é "nulável", podendo conter True, False e null. Por outro lado, pl.Null só pode conter null.
  2. Princípio de Substituição de Struct: Ao usar schema_overrides para substtiuir campos internos de uma Struct, é necessário fornecer a definição completa dos campos da Struct, caso contrário, os campos não mencionados serão descartados.
  3. 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.
  4. 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.

Tags: Polars JSONL.gz SchemaError Python Processamento de Dados

Publicado em 7-11 18:52