跳至內容

如何解決 AWS Glue 中的「無法推斷結構描述」錯誤?

2 分的閱讀內容
0

當我執行 AWS Glue 作業來處理儲存在 Amazon Simple Storage Service (Amazon S3) 中的 Parquet 或 ORC 檔案時,收到「無法推斷結構描述」錯誤。

簡短描述

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 中的「無法推斷結構描述」錯誤,請根據您的使用案例使用下列其中一種方法。

重新架構您的資料

將檔案複製到新的 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'
)

使用對應類別轉換來新增分區欄

若要將分區欄包含在 DynamicFrame 中,請將資料讀入 DataFrame,並為 Amazon S3 檔案路徑新增一欄。然後,套用對應類別轉換。

程式碼範例:

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 輸出的分區

AWS 官方已更新 1 年前