Comment résoudre l'exception « Unable to Infer Schema » (Impossible d'inférer le schéma) dans AWS Glue ?

Date de la dernière mise à jour : 12/06/2019

Ma tâche AWS Glue échoue avec l'une des exceptions suivantes :

  • « AnalysisException: u'Unable to infer schema for Parquet. It must be specified manually » (AnalysisException : Impossible d'inférer le schéma pour Parquet. Il doit être défini manuellement.)
  • « AnalysisException: u'Unable to infer schema for ORC. It must be specified manually » (AnalysisException : Impossible d'inférer le schéma pour Parquet. Il doit être défini manuellement.)

Brève description

Cette erreur se produit généralement lorsqu'AWS Glue essaie de lire un fichier Parquet ou ORC qui n'est pas stocké dans un chemin partitionné de type Apache Hive qui utilise la structure key=val. AWS Glue s'attend à ce que les fichiers sources Amazon Simple Storage Service (Amazon S3) se trouvent dans des paires clé-valeur. Par exemple, si la tâche AWS Glue traite les fichiers dans s3://s3-bucket/parquet-data/, les fichiers doivent avoir la structure de partition suivante :

s3://s3-bucket/parquet-data/year=2018/month=10/day=10/file1.parquet

Si les fichiers Parquet ou ORC sont stockés dans une structure hiérarchique, la tâche AWS Glue échoue avec l'exception « Unable to infer schema » (Impossible d'inférer le schéma). Exemple :

s3://s3-bucket/parquet-data/year/month/day/file1.parquet

Résolution

Utilisez l'une des méthodes suivantes pour éliminer l'erreur.

Restructurer vos données

Copiez les fichiers vers un nouveau compartiment S3 et utilisez des chemins partitionnés de type Hive. Exécutez de nouveau la tâche.

Remplacer les noms des colonnes de partition par des astérisques

Si la restructuration de vos données n'est pas possible, créez le DynamicFrame directement depuis Amazon S3. Dans le chemin Amazon S3, remplacez tous les noms des colonnes de partition par des astérisques (*). Lorsque vous utilisez cette solution, AWS Glue n'inclut pas les colonnes de partition dans le DynamicFrame ; il inclut uniquement les données.

Supposons que vos fichiers sont stockés dans un compartiment S3 avec la structure de partition suivante :

s3://s3-bucket/parquet-data/year/month/day/files.parquet

Pour traiter tous les fichiers dans le chemin s3://s3-bucket/parquet-data/, créez le DynamicFrame comme suit :

dynamic_frame0 = glueContext.create_dynamic_frame_from_options('s3',connection_options={'paths':['s3://s3-bucket/parquet-data/*/*/*'],},format="parquet",transformation_ctx = "dynamic_frame0")

Utiliser une transformation de mappe pour ajouter des colonnes de partition

Pour inclure les colonnes de partition dans le DynamicFrame, créez un DataFrame, puis ajoutez une colonne pour le chemin de fichier Amazon S3. Ensuite, créez le DynamicFrame et appliquez une transformation de mappe pour ajouter les colonnes de partition, comme indiqué dans l'exemple suivant. Avant d'utiliser l'exemple de code, remplacez les chemins Amazon S3 et saisissez les noms des colonnes de partition en utilisant les valeurs d'index correctes.

import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from awsglue.dynamicframe import DynamicFrame
from pyspark.sql.functions import *
args = getResolvedOptions(sys.argv, ['JOB_NAME'])
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)
df= spark.read.parquet("s3://s3-bucket/parquet-data/*/*/*")
modified_df = df.withColumn('partitions_column',input_file_name())
dyf_0 = DynamicFrame.fromDF(modified_df, glueContext, "dyf_0")

def modify_col(x):
     if x['partitions_column']:
        new_columns = x['partitions_column'].split('/')
        x['year'],x['month'],x['day'] = new_columns[4],new_columns[5],new_columns[6]
        del x['partitions_column']
     return x

modified_dyf = Map.apply(dyf_0,f=modify_col)
datasink2 = glueContext.write_dynamic_frame.from_options(frame =modified_dyf , connection_type = "s3", connection_options = {"path": "s3://my-output-bucket/output/","partitionKeys": ["year","month","day"]}, format = "parquet", transformation_ctx = "datasink2")

Pour plus d'informations sur l'application des transformations de mappe, consultez Classe de mappe.


Cet article vous a-t-il été utile ?

Cette page peut-elle être améliorée ?


Vous avez besoin d'aide ?