【トラブル】【AWS】Hiveテーブルデータ を Redshift に移行時のCOPYコマンドエラー

■ はじめに

https://dk521123.hatenablog.com/entry/2021/09/01/200818

において、Hiveテーブルデータ を Redshift に移行する際に
COPYコマンドにおいていくつかトラブルが発生したので
まとめておく。

目次

【1】COPYコマンド時にエラー「Forbidden: HTTP response error code 403」が発生
【2】COPYコマンド時にエラー「Check 'stl_load_errors' system table for details.」が発生

【1】COPYコマンド時にエラー「Forbidden: HTTP response error code 403」が発生

https://dk521123.hatenablog.com/entry/2021/09/01/200818

で行ったHiveテーブルデータ を Redshift に移行において、
Hive/Redshiftを以下のように行ったら、以下の「1)エラー内容」が発生した。

[現象発生時] Hive Part

CRATE EXTERNAL TABLE sample_table(
  id STRING,
  name STRING,
  col1 STRING,
  col2 STRING,
  created_at TIMESTAMP
)
STORED AS PARQUET
TBLPROPERTIES("parquet.compression"="SNAPPY")
LOCATION 's3://your-s3-bucket/xxxx/sample_db/sample_table/'
;

[現象発生時] Redshift part : COPYコマンド

COPY redshift_db_name.redshift_sample_table
FROM 's3://your-s3-bucket/xxxx/sample_db/sample_table/' 
iam_role 'arn:aws:iam::XXXXXXXXXXX:role/for-redshift-role'
parquet
REGION 'us-west-2';

1)エラー内容

ERROR: Spectrum Scan Error
DETAIL:
-----------------------------------------------
 error:  Spectrum Scan Error
 code:      15007
 context:   Forbidden: HTTP response error code 403
 Message: AccessDenied Access Denied
 x-amz-request-id: xxxx
 x-amz-id-2: xxxx
 query: xxxxxx
 location: dory_util.cpp:1136
 process: worker_thread [pid=xxxx]
 ----------------------------------------------

2)原因

S3の権限エラーっぽいけど、
Hive の Parquet と Redshift の Parquet で相性が悪いから??

補足1:権限問題の調査について

まずは、以下の2点を確認した方がいい。
~~~~~~~
1)COPYコマンドに付与している IAM role の権限の確認
2)COPY元のS3のバケットのアクセス権限の確認
~~~~~~~

そして、公式サイトの「S3ServiceException エラー」を頼りに、
ロール問題かどうかを詳細に調査した方がいいと思う。

https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/s3serviceexception-error.html

補足2:調査メモ

以下のようにディレクトリ構成でファイルができていた。
~~~~~~
s3://your-s3-bucket/xxxx/sample_db/sample_table/
 1/xxxx
 2/xxxx
~~~~~~

そこでものは試しに、手動で、以下のように構成変更して
色々試したけど、同じエラーになってしまった。。。
~~~~~~
[変更後]
s3://your-s3-bucket/xxxx/sample_db/sample_table/
 xxxx1
 xxxx2

[試したこと]
[Errror] COPY ... FROM 's3://your-s3-bucket/xxxx/sample_db/sample_table/' 
[Errror] COPY ... FROM 's3://your-s3-bucket/xxxx/sample_db/sample_table/xxxx1' 
~~~~~~

3)解決案

Hiveの保存をparquetから変更したら、エラーが解消された。

フルソースは、以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2021/09/01/200818

[修正後] Hive part

-- GZIP形式で圧縮する
set hive.exec.compress.output=true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec;

CRATE EXTERNAL TABLE sample_table(
  id STRING,
  name STRING,
  col1 STRING,
  col2 STRING,
  created_at TIMESTAMP
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\001'
STORED AS TEXTFILE
LOCATION 's3://your-s3-bucket/xxxx/sample_db/sample_table/'
;

[修正後] Redshift part (COPYコマンド)

COPY redshift_db_name.redshift_sample_table
FROM 's3://your-s3-bucket/xxxx/sample_db/sample_table/' 
iam_role 'arn:aws:iam::XXXXXXXXXXX:role/for-redshift-role'
DELIMITER '\001'
gzip
NULL 'NULL'
REGION 'us-west-2';

【2】COPYコマンド時にエラー「Check 'stl_load_errors' system table for details.」が発生

『【1】COPYコマンド時にエラー「Forbidden: HTTP response error code 403」が発生』を
実行後、別のテーブルのCOPYコマンド時に、以下「1)エラー内容」のエラーが発生した。

1)エラー内容

ERROR: Load into table 'xxxx' failed. Check 'stl_load_errors' system table for details.

2)原因

https://otiai10.hatenablog.com/entry/2015/12/22/183910

が非常に参考になった。本当にこういう記事はありがたいです、、、

原因・Case1

最終的には、データがテーブルに定義した範囲を超えていたため。
(例として、VERCHAR(100) で定義していたデータ項目に、
 100文字を超えた文字列を格納しようとしていた)

原因・Case2

Integerで定義している項目に対して、
文字列「${xxxx}」を格納しようとしていたため。

3)補足:調査内容

https://otiai10.hatenablog.com/entry/2015/12/22/183910

を参照。

以下は、自分の確認した調査手順。
「String length exceeds DDL length」とあったので、
上記「2)原因」であることが突き止められた

[1] psqlでログイン

psql -U ${USER} -h ${HOST} -p ${PORT} ${DB_NAME}

[2] システムテーブル「stl_load_errors」テーブルの確認

\d stl_load_errors;

[3] エラー内容確認 / Case1

SELECT starttime, TRIM(colname), err_code, TRIM(err_reason)
FROM stl_load_errors
ORDER BY starttime DESC LIMIT 2;

[出力結果](「String length exceeds DDL length」を確認)
         starttime          | btrim  | err_code |                     btrim
----------------------------+--------+----------+------------------------------------------------
 20XX-XX-XX XX:47:17.143206 |  column_name   |     1204 | String length exceeds DDL length
 20XX-XX-XX XX:15:05.32209  |   column_name     |     1204 | String length exceeds DDL length
(2 rows)

[3] エラー内容確認 / Case2

[出力結果](「String length exceeds DDL length」を確認)
         starttime          | btrim  | err_code |                     btrim
----------------------------+--------+----------+------------------------------------------------
 20XX-XX-XX XX:47:17.143206 |  column_name   |     1207 | Invalid digit, Value '$', Pos 0, Type: Integer
 20XX-XX-XX XX:15:05.32209  |   column_name     |     1207 | Invalid digit, Value '$', Pos 0, Type: Integer
(2 rows)

4)解決案

Case1の解決案

テーブルの定義域を拡張した。
~~~~~~~
VERCHAR(100) => VERCHAR(200)
~~~~~~~

Case2の解決案

数字になるように元データ側を修正

関連記事

Hiveテーブルデータ を Redshift に移行するには
https://dk521123.hatenablog.com/entry/2021/09/01/200818
Amazon Redshift ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/02/22/002139
Amazon Redshift ~ COPY コマンド ~
https://dk521123.hatenablog.com/entry/2021/07/21/214248
よく使う pdqlコマンド
https://dk521123.hatenablog.com/entry/2020/01/10/224818