RedshiftでJSONファイルをCOPYする時にはキー名の大文字小文字に注意!
はじめに
こんにちは。DI部の大高です。
先日、JSONファイルのCOPY時にうまくCOPYできないケースに遭遇しました。私はこのケースを初めて知ったのでご紹介したいと思います。
主旨としてはタイトルの通り「JSONのキー名の大文字小文字の違いによってCOPYできないことがある」という話になります。
やりたいこと
S3に配置してあるJSON(JSONL)ファイルをRedshiftのテーブルのCOPY文でロードしたいと思います。
なお、やり方に関しては以下のヘルプが参考になります。
では、早速やっていきます。
ロード先のテーブル
Redshift上に以下のように事前にテーブルを作成します。(スキーマ ootaka_sandbox
は事前に作成したものです)
CREATE TABLE ootaka_sandbox.users( Id INTEGER, Username NVARCHAR(512), PRIMARY KEY(Id) ) DISTSTYLE EVEN ;
JSONファイル
JSONファイルは以下の2ファイルを用意します。1つ目の users_camel.json
はキー名の先頭が大文字のもの(テーブル作成時と同じ)、2つ目の users_lower.json
はキー名がすべて小文字のものです。
{"Id": 1, "Username": "Sougo"} {"Id": 2, "Username": "Geiz"} {"Id": 3, "Username": "Woz"}
{"id": 1, "username": "Sougo"} {"id": 2, "username": "Geiz"} {"id": 3, "username": "Woz"}
用意したら、Resdhitから参照できるように設定済みのS3バケットにアップロードしておきます。
COPYしてみる
用意したJSONを利用してCOPYしてみます。
users_camel.json
COPY文は以下のようになります。
COPY ootaka_sandbox.users FROM 's3://ootaka_sandbox/json/users_camel.json' IAM_ROLE 'arn:aws:iam::999999999999:role/redshift-role' FORMAT AS JSON 'auto';
実行するとエラーが発生しました。
XX000: Load into table 'users' failed. Check 'stl_load_errors' system table for details.
stl_load_errors
テーブルを確認してみます。
SELECT filename , line_number , colname , position , raw_line , err_reason FROM stl_load_errors ORDER BY starttime DESC LIMIT 1 ;
すると、 err_reason
カラムには、 Missing data for not-null field
が入っていました。日本語だと NOT NULL として指定されたフィールドにデータが含まれていませんでした。
です。
すなわち、プライマリキーとしてNOT NULLにしていた Id
カラムに値が無いと言っています。
原因は、JSONのキー名の大文字小文字です。Reshiftでテーブル作成をすると、Redshift上のカラム名はすべて小文字となるのでCREATE TABLE文でカラム名を Id
と指定しても、実際には id
となります。一方で、JSONのキー名は Id
なので、認識してくれなかったという理由です。
users_camel.json
では、キー名が小文字のもので再チャレンジしてみます。COPY文は以下です。
COPY ootaka_sandbox.users FROM 's3://ootaka_sandbox/json/users_lower.json' IAM_ROLE 'arn:aws:iam::999999999999:role/redshift-role' FORMAT AS JSON 'auto';
こちらはエラーが起きずに成功しました。
回避策
回避策の1つとしてJSONPathsファイルの利用があります。以下のようなファイルを用意して、カラムのマッピングを行います。
{ "jsonpaths": [ "$['Id']", "$['Username']" ] }
このファイルをS3に配置して以下のようにロードします。
COPY ootaka_sandbox.users FROM 's3://ootaka_sandbox/json/users_camel.json' IAM_ROLE 'arn:aws:iam::999999999999:role/redshift-role' JSON 's3://ootaka_sandbox/json/users_jsonpath.json';
こうすることで、先頭が大文字のキー名を各カラムにマッピングすることができ、問題なくCOPYすることができました。
まとめ
以上、JSONファイルのCOPYについてでした。JSONファイルのキー名に大文字小文字が利用されているケースは割りとあるかと思いますので、うまくCOPYできない場合には思い出して頂ければ幸いです。それでは!