Athena에서 AWS Config의 파일을 읽을 때 "HIVE_CURSOR_ERROR: Row is not a valid JSON Object - JSONException: Duplicate key"를 어떻게 해결해야 합니까?
최종 업데이트 날짜: 2019년 12월 9일
Amazon Athena를 사용하여 AWS Config 파일을 쿼리하면 "Error: HIVE_CURSOR_ERROR: Row is not a valid JSON Object - JSONException: Duplicate key" 오류가 표시됩니다.
간략한 설명
일반적으로 이 오류는 AWS Config 리소스에 동일한 이름으로 된 태그가 여러 개 있고, 일부 태그는 대문자이고 일부 태그는 소문자일 때 발생합니다. 예를 들어 다음 레코드는 tc:Name과 tc:name JSON 키를 사용합니다.
{
"fileVersion": "1.0",
"configSnapshotId": "35eced35-a13a-45b7-81e4-446e35616e70",
"configurationItems": [
{
"tags": { "tc:Name": "6", "tc:name": "abc6-38" }
},
{
"tags": { "tc:Name": "6", "tc:name": "abc6-38" }
},
{
"tags": { "tc:Name": "6" }
},
{
"tags": { "tc:name": "6" }
}
]
}
해결 방법
다음과 비슷한 CREATE TABLE 문을 실행합니다. 이 문은 Athena 테이블을 생성하고, case.insensitive를 false로 설정하고, 열 이름을 열 이름과 동일하지 않은 JSON 키로 매핑합니다. 이 문을 실행하기 전에:
- LOCATION 필드에서 s3://awsexamplebucket/AWSLogs/를 Amazon Simple Storage Service(Amazon S3) 버킷으로 변경합니다.
- 모든 매핑 속성을 열 이름과 JSON 키(예: mapping.fileversion'='fileVersion')로 변경합니다.
CREATE EXTERNAL TABLE aws_config_configuration_snapshot (
fileversion STRING,
configsnapshotid STRING,
configurationitems ARRAY < STRUCT <
configurationItemVersion : STRING,
configurationItemCaptureTime : STRING,
configurationStateId : BIGINT,
awsAccountId : STRING,
configurationItemStatus : STRING,
resourceType : STRING,
resourceId : STRING,
resourceName : STRING,
ARN : STRING,
awsRegion : STRING,
availabilityZone : STRING,
configurationStateMd5Hash : STRING,
configuration : STRING,
supplementaryConfiguration : MAP < STRING, STRING >,
tags: MAP < STRING, STRING >,
resourceCreationTime : STRING > >
)
PARTITIONED BY ( dt STRING , region STRING )
ROW FORMAT SERDE
'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
<b>'case.insensitive'='false'</b>,
'mapping.fileversion'='fileVersion',
'mapping.configsnapshotid'='configSnapshotId',
'mapping.configurationitems'='configurationItems',
'mapping.configurationitemversion'='configurationItemVersion',
'mapping.configurationitemcapturetime'='configurationItemCaptureTime',
'mapping.configurationstateid'='configurationStateId',
'mapping.awsaccountid'='awsAccountId',
'mapping.configurationitemstatus'='configurationItemStatus',
'mapping.resourcetype'='resourceType',
'mapping.resourceid'='resourceId',
'mapping.resourcename'='resourceName',
'mapping.arn'='ARN',
'mapping.awsregion'='awsRegion',
'mapping.availabilityzone'='availabilityZone',
'mapping.configurationstatemd5hash'='configurationStateMd5Hash',
'mapping.supplementaryconfiguration'='supplementaryConfiguration',
'mapping.configurationstateid'='configurationStateId'
)<br>LOCATION 's3://awsexamplebucket/AWSLogs/';
이미 파티션이 로드된 테이블이 있을 경우, 다음과 같이 새 SerDe 속성을 테이블에 추가할 수 있습니다.
ALTER TABLE aws_config_configuration_snapshot SET TBLPROPERTIES (
'case.insensitive'='false',
'mapping.fileversion'='fileVersion',
'mapping.configsnapshotid'='configSnapshotId',
'mapping.configurationitems'='configurationItems',
'mapping.configurationitemversion'='configurationItemVersion',
'mapping.configurationitemcapturetime'='configurationItemCaptureTime',
'mapping.configurationstateid'='configurationStateId',
'mapping.awsaccountid'='awsAccountId',
'mapping.configurationitemstatus'='configurationItemStatus',
'mapping.resourcetype'='resourceType',
'mapping.resourceid'='resourceId',
'mapping.resourcename'='resourceName',
'mapping.arn'='ARN',
'mapping.awsregion'='awsRegion',
'mapping.availabilityzone'='availabilityZone',
'mapping.configurationstatemd5hash'='configurationStateMd5Hash',
'mapping.supplementaryconfiguration'='supplementaryConfiguration',
'mapping.configurationstateid'='configurationStateId')
테이블이 준비되면 configurationItem.tags['TAGNAME']를 사용하여 태그에 액세스할 수 있습니다. 예를 들어 tc:Name 태그에 액세스하려면 다음 쿼리를 실행합니다.
SELECT configurationItem.tags['tc:Name']
FROM your_table
CROSS JOIN unnest(configurationItems) AS t(configurationItem)
WHERE configurationItem.tags['tc:Name'] IS NOT NULL