こんにちは、CX事業本部 IoT事業部の若槻です。
Amazon AthenaのOpenX JSON SerDeでは、SerDeのオプションとして次のプロパティを設定することができます。(説明は後述)
プロパティ名 | 既定値 |
---|---|
ignore.malformed.json | FALSE |
dots.in.keys | FALSE |
case.insensitive | FALSE |
mapping | - |
今回は、上記オプションプロパティの設定の有無による動作の違いを確認してみました。
やってみた
OpenX JSON SerDeのオプションプロパティがデフォルトのテーブルと設定されたテーブルを作成し、それぞれの動作を見てみます。
まず既定のプロパティのテーブルcounts_default
を作成します。
CREATE EXTERNAL TABLE counts_default(
id string,
a_b string,
count int
)
ROW FORMAT
SERDE
'org.openx.data.jsonserde.JsonSerDe'
STORED AS
INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://cm-test-220801/counts'
TBLPROPERTIES ('has_encrypted_data'='false')
次に、それぞれのオプションプロパティを既定値から変更したテーブルcounts_optional
を作成します。
CREATE EXTERNAL TABLE counts_optional(
id string,
a_b string,
count int
)
ROW FORMAT
SERDE
'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES ("ignore.malformed.json" = "TRUE", "dots.in.keys" = "TRUE", "case.insensitive" = "FALSE", "mapping.count"= "cnt")
STORED AS
INPUTFORMAT
'org.apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION 's3://cm-test-220801/counts'
TBLPROPERTIES ('has_encrypted_data'='false')
ignore.malformed.json
不正なレコードを含むデータを作成します。
$ cat data
{"id":"u001","count":3,"a.b":"あああ"}
{いいい}
{"id":"u003","count":2,"a.b":"ううう"}
$ DATA_BUCKET_NAME="cm-test-220801"
$ aws s3 cp data s3://${DATA_BUCKET_NAME}/counts/data
デフォルト設定のテーブル("ignore.malformed.json" = "FALSE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_default
クエリがエラーとなりました。
SerDeのオプションを設定したテーブル("ignore.malformed.json" = "FALSE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_optional
不正なレコードを無視して、有効なレコードのみ取得できました。
dots.in.keys
JSON SerDeでは.
を含むスキーマを定義することができませんが、SerDeでdots.in.keys
がTRUE
の場合、データのプロパティ中のドット.
をアンダースコア_
に置き換えてクエリすることができるようになります。
テーブルが持つa_b
スキーマのアンダースコア_
をドット.
に置き換えたa.b
プロパティを持つデータを作成します。
$ cat data
{"id":"u001","count":3,"a.b":"あああ"}
{"id":"u002","count":1,"a.b":"いいい"}
{"id":"u003","count":2,"a.b":"ううう"}
$ DATA_BUCKET_NAME="cm-test-220801"
$ aws s3 cp data s3://${DATA_BUCKET_NAME}/counts/data
デフォルト設定のテーブル("dots.in.keys" = "FALSE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_default
a_b
プロパティの値は取得できていません。
SerDeのオプションを設定したテーブル("dots.in.keys" = "TRUE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_optional
データ中のa.b
プロパティがa_b
に置き換えられて取得できました。
case.insensitive
SerDeでcase.insensitive
プロパティがFALSE
の場合、データのプロパティ名の大文字/小文字が厳密に扱われます。
count
プロパティが大文字となったレコードを含むデータを作成します。
$ data
$ cat $DATA_FILE_NAME
{"id":"u001","COUNT":3}
{"id":"u002","count":1}
{"id":"u003","count":2}
$ DATA_BUCKET_NAME="cm-test-220801"
$ aws s3 cp data s3://${DATA_BUCKET_NAME}/counts/data
デフォルト設定のテーブル("case.insensitive" = "TRUE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_default
実際のデータがCOUNT
またはcount
のいずれかに関わらず、いずれもcount
プロパティとして取得されました。
SerDeのオプションを設定したテーブル("case.insensitive" = "FALSE"
)に対してSELECTクエリした場合。
SELECT * FROM counts_optional
実際のデータがcount
の場合のみ取得されました。
mapping
SerDeでmapping
プロパティを使用すると、実際のデータとテーブルのスキーマの間でプロパティ名をマッピングすることができます。
マッピング対象のプロパティcnt
を含むデータを作成します。
$ cat data
{"id":"u001","a_b":"あああ","cnt":3}
{"id":"u002","a_b":"いいい","cnt":1}
{"id":"u003","a_b":"ううう","cnt":2}
$ DATA_BUCKET_NAME="cm-test-220801"
$ aws s3 cp data s3://${DATA_BUCKET_NAME}/counts/data
デフォルト設定のテーブルに対してSELECTクエリした場合。
SELECT * FROM counts_default
データのcount
プロパティは取得できません。
SerDeのオプションを設定したテーブル("mapping.count"= "cnt"
)に対してSELECTクエリした場合。
SELECT * FROM counts_optional
データのcnt
プロパティがcount
として取得できました。
おわりに
Amazon AthenaのOpenX JSON SerDeのオプションプロパティを試してみました。
このようにOpenX JSON SerDeは便利ですが、Hive JSON SerDeで利用可能なINSERT INTOが使えないという制限もあります。両者をうまく使い分けたいですね。
以上