OpenX JSON SerDe - Amazon Athena

OpenX JSON SerDe

Hive JSON SerDe와 마찬가지로 OpenX JSON을 사용하여 JSON 데이터를 처리할 수 있습니다. 데이터는 새 줄로 구분된 JSON 인코딩 텍스트의 한 줄 문자열로도 표시됩니다. Hive JSON SerDe와 마찬가지로 OpenX JSON SerDe는 map 또는 struct 키 이름에 중복 키를 허용하지 않습니다.

고려 사항 및 제한

  • OpenX JSON SerDe를 사용하는 경우 결과의 수 및 값이 비결정적일 수 있습니다. 결과에는 예상보다 많거나 적은 수의 행 또는 기본 데이터에 없는 예상치 못한 null 값이 포함될 수 있습니다. 이 문제를 해결하려면 Hive JSON SerDe를 사용하거나 데이터를 다른 파일 형식으로 다시 쓰세요.

  • SerDe는 각 JSON 문서가 레코드의 필드를 구분하는 줄 종료 문자가 없는 한 줄의 텍스트에 있을 것으로 예상합니다. JSON 텍스트가 가독성 좋게 꾸민 형식이면 테이블을 만든 후 쿼리하려고 할 때 HIVE_CURSOR_ERROR: 행이 유효한 JSON 객체가 아님(HIVE_CURSOR_ERROR: Row is not a valid JSON Object) 또는 HIVE_CURSOR_ERROR: JsonParseException: 예기치 않은 입력 종료: OBJECT의 닫기 마커 필요(HIVE_CURSOR_ERROR: JsonParseException: Unexpected end-of-input: expected close marker for OBJECT) 같은 오류 메시지가 나타날 수 있습니다.

    자세한 내용은 GitHub의 OpenX SerDe 문서에서 JSON 데이터 파일을 참조하세요.

선택적 속성

Hive JSON SerDe와 달리 OpenX JSON SerDe에는 데이터의 불일치를 해결하는 데 유용한 다음과 같은 선택적 SerDe 속성이 있습니다.

ignore.malformed.json

선택 사항입니다. TRUE로 설정하면 형식이 잘못된 JSON 구문을 건너뛸 수 있습니다. 기본값은 FALSE입니다.

dots.in.keys

선택 사항입니다. 기본값은 FALSE입니다. TRUE로 설정하면 SerDe가 키 이름의 점을 밑줄로 바꿀 수 있습니다. 예를 들어 JSON 데이터 세트에 이름이 "a.b"인 키가 있을 경우 이 속성을 사용하여 Athena에서 열 이름이 "a_b"가 되도록 정의할 수 있습니다. 이 SerDe가 없으면 기본적으로 Athena는 열 이름에 점을 허용하지 않습니다.

case.insensitive

선택 사항입니다. 기본값은 TRUE입니다. TRUE로 설정하면 SerDe가 모든 대문자 열을 소문자로 변환합니다.

데이터에서 대/소문자를 구분하는 키 이름을 사용하려면 WITH SERDEPROPERTIES ("case.insensitive"= FALSE;)를 사용합니다. 그런 다음, 아직 모두 소문자가 아닌 모든 키에 대해 다음 구문을 사용하여 열 이름에서 속성 이름으로 매핑을 제공합니다.

ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ("case.insensitive" = "FALSE", "mapping.userid" = "userId")

URLUrl와 같이 소문자로 동일한 두 개의 키가 있는 경우, 다음과 같은 오류가 발생할 수 있습니다.

HIVE_CURSOR_ERROR: 행이 유효한 JSON 객체가 아님 - JSONException: 중복 키 "url"

이 문제를 해결하려면 다음 예제와 같이 case.insensitive 속성을 FALSE로 설정하고 키를 다른 이름으로 매핑합니다.

ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ("case.insensitive" = "FALSE", "mapping.url1" = "URL", "mapping.url2" = "Url")
매핑

선택 사항입니다. 열 이름을, 열 이름과 동일하지 않은 JSON 키에 매핑합니다. mapping 파라미터는 JSON 데이터에 키워드인 키가 있을 경우에 유용합니다. 예를 들어 timestamp라는 JSON 키가 있는 경우 다음 구문을 사용하여 키를 ts라는 열에 매핑합니다.

ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ("mapping.ts" = "timestamp")
Hive 호환 이름에 콜론이 있는 중첩된 필드 이름 매핑

struct 내에 콜론이 있는 필드 이름이 있는 경우 mapping 속성을 사용하여 Hive 호환 이름에 필드를 매핑할 수 있습니다. 예를 들어 열 유형 정의에 my:struct:field:string이 포함된 경우 WITH SERDEPROPERTIES에 다음 항목을 포함하여 my_struct_field:string에 정의를 매핑할 수 있습니다.

("mapping.my_struct_field" = "my:struct:field")

다음 예제에서는 해당 CREATE TABLE 문을 보여줍니다.

CREATE EXTERNAL TABLE colon_nested_field ( item struct<my_struct_field:string>) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ("mapping.my_struct_field" = "my:struct:field")

예제: 광고 데이터

다음 예제 DDL 문은 OpenX JSON SerDe를 사용하여 Hive JSON SerDe의 예제에 사용된 것과 동일한 샘플 온라인 광고 데이터를 기반으로 테이블을 생성합니다. LOCATION 절에서 myregion을, Athena를 실행하는 리전 식별자로 바꿉니다.

CREATE EXTERNAL TABLE impressions ( requestbegintime string, adid string, impressionId string, referrer string, useragent string, usercookie string, ip string, number string, processid string, browsercokie string, requestendtime string, timers struct< modellookup:string, requesttime:string>, threadid string, hostname string, sessionid string ) PARTITIONED BY (dt string) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://amzn-s3-demo-bucket.elasticmapreduce/samples/hive-ads/tables/impressions';

예제: 중첩 JSON 역직렬화

JSON SerDes를 사용하여 더 복잡한 JSON 인코딩 데이터를 구문 분석 할 수 있습니다. 이를 위해서는 structarray 요소를 사용하여 중첩 구조를 나타내는 CREATE TABLE 문을 사용해야 합니다.

다음 예제에서는 중첩 구조가 있는 JSON 데이터로 Athena 테이블을 생성합니다. 예제의 구조는 다음과 같습니다.

{ "DocId": "AWS", "User": { "Id": 1234, "Username": "carlos_salazar", "Name": "Carlos", "ShippingAddress": { "Address1": "123 Main St.", "Address2": null, "City": "Anytown", "State": "CA" }, "Orders": [ { "ItemId": 6789, "OrderDate": "11/11/2022" }, { "ItemId": 4352, "OrderDate": "12/12/2022" } ] } }

OpenX SerDe는 각 JSON 레코드가 한 줄의 텍스트에 있을 것으로 예상한다는 점을 기억하세요. Amazon S3에 저장되는 경우 이전 예제의 모든 데이터는 다음과 같이 한 줄에 있어야 합니다.

{"DocId":"AWS","User":{"Id":1234,"Username":"carlos_salazar","Name":"Carlos","ShippingAddress" ...

다음 CREATE TABLE 문은 Openx-JsonSerDestructarray 컬렉션 데이터 형식을 사용하여 예제 데이터에 대한 객체 그룹을 설정합니다.

CREATE external TABLE complex_json ( docid string, `user` struct< id:INT, username:string, name:string, shippingaddress:struct< address1:string, address2:string, city:string, state:string >, orders:array< struct< itemid:INT, orderdate:string > > > ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' LOCATION 's3://amzn-s3-demo-bucket/myjsondata/';

테이블을 쿼리하려면 다음과 같은 간단한 SELECT 문을 사용합니다.

SELECT user.name as Name, user.shippingaddress.address1 as Address, user.shippingaddress.city as City, o.itemid as Item_ID, o.orderdate as Order_date FROM complex_json, UNNEST(user.orders) as temp_table (o)

샘플 쿼리는 구조체 내의 데이터 필드에 액세스하기 위해 점 표기법(예: user.name)을 사용합니다. orders 필드와 마찬가지로 구조체 배열 내의 데이터에 액세스하려면 UNNEST 함수를 사용하면 됩니다. UNNEST 함수는 배열을 임시 테이블(이 경우 o)로 평면화합니다. 이렇게 하면 구조체와 마찬가지로 점 표기법을 사용하여 중첩되지 않은 배열 요소에 액세스할 수 있습니다(예: o.itemid). 예제에서 설명용으로 사용되는 temp_table 이름은 보통 t와 같이 축약됩니다.

다음 표는 쿼리 결과를 보여 줍니다.

# 명칭 Address 구/군/시 Item_ID Order_date
1 Carlos 123 Main St. Anytown 6789 2022/11/11
2 Carlos 123 Main St. Anytown 4352 2022/12/12