当我运行 AWS Glue 作业来处理我存储在 Amazon Simple Storage Service (Amazon S3) 中的 Parquet 或 ORC 文件时,我收到了“Unable to infer schema”(无法推断架构)错误。
简短描述
Parquet 或 ORC 文件必须遵循 Hive 风格的 key=value 分区路径格式。如果文件改用分层路径结构,AWS Glue 将无法理解其架构并失败。
例如,如果您的 AWS Glue 作业处理来自 s3://s3-bucket/parquet-data/ 的文件,则这些文件必须使用以下分区格式:
s3://s3-bucket/parquet-data/year=2018/month=10/day=10/file1.parquet
如果这些文件使用以下非分区格式,则 AWS Glue 作业将失败:
s3://s3-bucket/parquet-data/year/month/day/file1.parquet
解决方法
要解决 AWS Glue 中的“Unable to infer schema”(无法推断架构)错误,请针对您的用例使用以下方法之一。
重组您的数据
将文件复制到新的 S3 存储桶,并使用 Hive 风格的分区路径。然后,运行作业。
用星号替换分区列名称
如果您无法重组数据,请直接从 Amazon S3 创建 DynamicFrame。使用星号 (*) 代替分区列名称。AWS Glue 仅包含 DynamicFrame 中的数据,不包含分区列。
例如,如果您将文件存储在文件路径为 s3://s3-bucket/parquet-data/year/month/day/files.parquet 的 S3 存储桶中,请使用以下 DynamicFrame:
dynamic_frame0 = glueContext.create_dynamic_frame_from_options(
's3',
connection_options={'paths': ['s3://s3-bucket/parquet-data/*/*/*']},
format='parquet',
transformation_ctx='dynamic_frame0'
)
使用 map 类转换添加分区列
要在 DynamicFrame 中包含分区列,请将数据读取到 DataFrame 中,然后为 Amazon S3 文件路径添加一列。然后,应用 map 类转换。
示例代码:
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 input_file_name
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"
)
**注意:**请将示例 S3 路径替换为您的 S3 路径,并根据您的用例自定义分区列。
解决文件或前缀不存在的问题
如果路径中没有文件,请检查您是否删除或存档了这些文件。如果文件使用不同的前缀,请更新 AWS Glue 脚本中的 connection_options 参数,以指向正确的路径。此外,请检查目录表是否引用了缺失或过时的 S3 位置。如果表指向的文件缺失,则作业将失败,因为没有数据可供处理。
解决带有作业书签参数的作业在扫描旧文件时出现的问题
当您使用作业书签时,AWS Glue 会跟踪先前处理过的文件,并跳过时间戳较早的文件。如果作业找不到符合条件的新文件,则作业将失败,因为没有数据可供处理。
要解决此问题,请执行以下操作:
- 确认文件修改后的时间戳在预期范围内。
- 关闭书签以重新处理所有文件。
- 重命名或更新这些文件,使其具有更新的上次修改时间戳,以便 AWS Glue 可以将其检测为新文件,并在下次运行时包含这些文件。
相关信息
管理 AWS Glue 中用于 ETL 输出的分区