Athena의 구성 단위 분할 모드 불일치 오류 해결

16452 단어 awsathenaglue
CSV 파일과 AWS Glue, Athena와 같은 빅데이터 도구를 사용하는 것은 흥미로운 도전을 가져올 수 있다.이 블로그에서, 나는 너희들에게 내가 한 프로젝트에서 겪는 특수한 문제인 구성 단원 구역 모델이 일치하지 않는 것을 어떻게 해결하는지 설명할 것이다.
본고는 접착제와 그 구성 부분에 대해 약간의 기본적인 이해를 가지고 있다고 가정한다.서비스에 익숙하지 않은 경우 언제든지 전화하십시오check out my introduction to it.만약 당신이 이전에 아테나와 합작한 적이 있다면 그것도 도움이 될 것이다. 그러나 이것은 필수적인 지식이 아니다. 왜냐하면 이것은 문제를 일으킬 수 있는 유일한 도구이기 때문이다.우선, 우리는 몇 가지 설정부터 이 오류가 어떻게 발생했는지 설명할 것이다.

샘플 데이터


스크립트를 만들었습니다. 예시 데이터를 만들었습니다. 데이터를 처리할 때 이 오류가 발생합니다.할 수 있다find all of the code on GitHub.이 스크립트는 파티션 제품 테이블을 위한 데이터를 생성합니다.각 제품에는 공급업체 이름, 제품 이름, 가격, 수량 및 무게가 있습니다.이 제품들은 공급업체에 의해 구분된다. 비록 나의 예에서 이 공급업체들의 이름은 매우 재미있지만.다음은 두 데이터 샘플의 발췌문입니다.
공급업체: 이중 중량
"supplier_name";"product_name";"price";"quantity";"weight"
"double_with_weight";"Christopher";4339.26;8622;29
"double_with_weight";"Sean";9068.08;3501;28
"double_with_weight";"Danielle";4285.51;7612;2
"double_with_weight";"Rebecca";9009.99;1358;29
"double_with_weight";"Michelle";8097.9;3382;11
공급업체: 무게가 있는 int
"supplier_name";"product_name";"price";"quantity";"weight"
"int_with_weight";"Kayla";9092;793;50
"int_with_weight";"Danielle";9294;2365;46
"int_with_weight";"Kristy";4058;2989;7
"int_with_weight";"Kelli";2582;2887;14
"int_with_weight";"Rebekah";959;5627;26
이 데이터를 보면 공급업체가 왜 이렇게 이상한 이름을 가지고 있는지 알 수 있을 것이다.첫 번째 상황에서는 모든 가격이 십진수로 쌍정밀도나 부동점수를 나타내고 두 번째 상황에서는 정수이다.
저장소의 지침에 따라 작업하면 데이터는 다음과 같은 구조로 S3에 업로드됩니다.
└── products_partitioned
    ├── supplier=double_with_weight
    │   └── data.csv
    ├── supplier=double_without_weight
    │   └── data.csv
    ├── supplier=int_with_weight
    │   └── data.csv
    └── supplier=int_without_weight
        └── data.csv

물건을 한데 붙이다


이 키들을 사용하면 우리는 시스템에 데이터를 어떻게 구분하는지 알려줄 수 있다.우리는 구역 열을 supplier라고 부르고 데이터 파일이 해당 구역에 대한 값을 알려준다.Glue Crawler를 시작하면 Glue 메타데이터 디렉토리에 파티션 테이블을 만듭니다.다음은 파충류가 발견한 열과 데이터 형식입니다.

파충류 프로그램이 price열의 데이터 형식을 더블 열로 결정하는데, 이것은 정수와 더블 값을 나타낼 수 있을 것입니다.만약 우리가 지금 아테나를 사용하여 표에서 데이터를 얻는다면, 우리는 그것이 아무런 문제도 없이 모든 기록을 얻을 수 있기를 바란다.불행하게도, 이곳의 상황은 그렇지 않다. 우리는 벌집 구역 구분 패턴이 일치하지 않는다는 것을 얻었다.

오류:

HIVE_PARTITION_SCHEMA_MISMATCH: There is a mismatch between the table and partition schemas. The types are incompatible and cannot be coerced. The column 'price' in table 'datalake.products_partitioned' is declared as type 'double', but partition 'supplier=int_without_weight' declared column 'price' as type 'bigint'.


이것은 int_without_weight 라는 이름의 구역을 읽을 수 없다는 것을 알려 줍니다. 구역은 열 price가bigint 형식이고, 표에서 더블 형식이라고 하기 때문입니다.Glue 메타데이터 디렉토리에 있는 파티션을 살펴보면 이러한 상황이 실제로 나타납니다.

우리 어떻게 왔어요?


파충류는 모든 파일을 보고 파일마다 구분 정의를 만든 것 같습니다.왠지 모르게, 이것은 표 자체가 price열의 더블 데이터 형식을 얻어야 한다는 것을 결정한다. 아마도 정수를 수용할 수 있기 때문일 것이다. 그러나 이것은 현재의 추측이다.Athena가 테이블을 읽을 때, 이 차이를 처리할 수 없을 것 같습니다.bigint 형식의 열은 너무 큰 값을 포함할 수 있고, 이중 정밀도 데이터 형식은 표시할 수 없습니다.
만약 우리가 정확한 데이터 형식을 가진 구역에서만 데이터를 읽으면 됩니다. 아래의 조회가 실행될 때 문제가 없습니다.
-- Query that doesn't touch the int partitions
SELECT *
FROM "datalake"."products_partitioned"
WHERE supplier = 'double_without_weight'
    OR supplier = 'double_with_weight'
LIMIT 10;

우리 어떡하지?


데이터의 절반만 처리할 수 있는 것은 진정한 선택이 아니기 때문에 우리는 다른 해결 방안을 생각해 내야 한다.이런 상황에서 우리는 우리의 데이터를 알고, 이중 데이터 유형이 우리 제품 목록에 있을 수 있는 모든 정수 가격에 적응할 수 있다는 것을 안다.이것은 기본 테이블과 같은 데이터 형식을 가지도록 구역의 모든 price열을 업데이트할 수 있음을 의미한다.실제 데이터는 읽을 때만 데이터 형식으로 강제로 변환되기 때문에 테이블의 메타데이터만 변경됩니다.솔루션은 다음과 같습니다.
def main():

    database_name = "datalake"
    table_name = "products_partitioned"

    make_partitions_inherit_datatypes_of_table(
        database_name=database_name,
        table_name=table_name
    )

if __name__ == "__main__":
    main()
고맙습니다. 안녕히 계세요.
기다리다구역 계승표의 데이터 형식을 나누는 것은 그리 쉽지 않다, 그렇지?옳았어우리는 진정으로 이 기능을 실현해야 한다.아래의 실현을 보실 수 있습니다.그것은 네 부분으로 나뉜다.우선, 우리는 기표와 그 데이터 유형을 묘사한다.그 다음에, 우리는 이 표의 모든 구역을 열거한 다음에, 데이터 형식이 일치하지 않기 때문에 어떤 구역이 업데이트되어야 하는지 찾아낸다.넷째, 변경이 필요한 모든 구역을 업데이트합니다.
import boto3

def make_partitions_inherit_datatypes_of_table(database_name, table_name):
    glue_client = boto3.client("glue")

    # Get the data types of the base table
    table_response = glue_client.get_table(
        DatabaseName=database_name,
        Name=table_name
    )

    column_to_datatype = {
        item["Name"]: item["Type"] for item in table_response["Table"]["StorageDescriptor"]["Columns"]
    }

    # List partitions and datatypes

    partition_params = {
        "DatabaseName": database_name,
        "TableName": table_name,
    }
    response = glue_client.get_partitions(**partition_params)
    partitions = response["Partitions"]

    while "NextToken" in response:
        partition_params["NextToken"] = response["NextToken"]
        response = glue_client.get_partitions(**partition_params)

        partitions += response["Partitions"]

    print("Got", len(partitions), "partitions")

    partitions_to_update = []
    for partition in partitions:
        changed = False

        columns = partition["StorageDescriptor"]["Columns"]
        new_columns = []
        for column in columns:
            if column["Name"] in column_to_datatype and column["Type"] != column_to_datatype[column["Name"]]:
                changed = True

                # print(f"Changing type of {column['Name']} from {column['Type']} to {column_to_datatype[column['Name']]}")
                column["Type"] = column_to_datatype[column["Name"]]
            new_columns.append(column)

        partition["StorageDescriptor"]["Columns"] = new_columns

        if changed:
            partitions_to_update.append(partition)

    print(f"{len(partitions_to_update)} partitions of table {table_name} will be updated.")

    # Update partitions if necessary
    for partition in partitions_to_update:

        print(f"Updating {', '.join(partition['Values'])}")

        partition.pop("CatalogId")
        partition.pop("CreationTime")

        glue_client.update_partition(
            DatabaseName=partition.pop("DatabaseName"),
            TableName=partition.pop("TableName"),
            PartitionValueList=partition['Values'],
            PartitionInput=partition
        )
지금 코드를 실행하면 다음과 같은 출력이 표시됩니다.
$ python data_type_inheritance.py
Got 4 partitions
2 partitions of table products_partitioned will be updated.
Updating int_with_weight
Updating int_without_weight
완성된 후에, 우리는 마침내 Athena에서 우리의 표를 조회할 수 있었는데, 오류가 사라졌다.

Glue가 기본 테이블의 데이터 형식을 선택하면 이 데이터 형식은 모든 구역의 값을 수용할 수 있습니다. 이런 방법은 작동할 수 있습니다.내 경험에 의하면, 그것은 이 방면에서 상당히 잘하기 때문에, 이 해결 방안은 거기에 적합해야 한다.만약 상황이 그렇지 않다면, 먼저 기본 테이블의 데이터 형식을 바꾸고 스크립트를 실행해야 합니다.

요약


한 마디로 하면 어떤 상황에서 풀 파충류는 서로 다른 구역의 같은 열에 서로 다른 데이터 유형을 설정할 수 있다.많은 경우, 기본 테이블은 구역의 모든 데이터 포인트를 수용할 수 있는 데이터 형식을 얻을 수 있다.이 테이블에서 읽으려고 시도할 때, 설정 단위 구분 모드가 일치하지 않습니다.
여기 열거한 복구 프로그램은 기본 테이블에서 데이터 형식을 가져오고 기본적으로 계승을 적용하기 때문에 테이블의 모든 구역은 기본 테이블과 같은 데이터 형식을 가지게 됩니다.
시간을 내주셔서 감사합니다. 피드백, 질문 또는 걱정이 있으면 언제든지 제 이력서에 링크된 소셜 미디어 채널을 통해 연락 주세요.

좋은 웹페이지 즐겨찾기