この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに こんばんは、菅野です。 先日のブログエントリーで、Amazon S3 Select を使って CSV ファイルを取得してみました。 今回は JSON データを対象にしてみたいと思います。
データが JSON の場合に指定するパラメータ
データが CSV の場合には存在しなかったパラメータとして「InputSerialization.JSON.Type」が必要となります。
Type:"Lines"
- 1行が1レコードになっているタイプのデータを扱います
- このタイプのデータを「JSON Lines」と呼びます(http://jsonlines.org/)
{"id":1,"name":"りんご","price":90}
{"id":2,"name":"みかん","price":30}
{"id":3,"name":"柿","price":60}
{"id":4,"name":"キウイ","price":70}
{"id":5,"name":"梨","price":120}
Type:"Document"
- JSON Lines 以外の JSON を扱う時はこちらを指定します
- 以下のようにトップレベルがオブジェクトになっている JSON ファイルを扱う事ができます
{
"Records": [
{"id":1,"name":"りんご","price":90},
{"id":2,"name":"みかん","price":30},
{"id":3,"name":"柿","price":60},
{"id":4,"name":"キウイ","price":70},
{"id":5,"name":"梨","price":120}
]
}
トップレベルが配列になっている JSON ファイルについて
- 以下のような JSON ファイルはどちらのタイプを使っても結果が空となります(2018年4月27日現在)
[
{"id":1,"name":"りんご","price":90},
{"id":2,"name":"みかん","price":30},
{"id":3,"name":"柿","price":60},
{"id":4,"name":"キウイ","price":70},
{"id":5,"name":"梨","price":120}
]
どちらのタイプを使うべきか(2018年4月27日現在)
「JSON Lines」を対象とし、Type:"Lines" で使いましょう。 JSON Lines 形式以外のデータに対して Type:"Document" でアクセスすると、以下のように全体で1レコードとして扱われますので where による絞り込みができません。
{"Records":[{"id":1,"name":"りんご","price":90},{"id":2,"name":"みかん","price":30},{"id":3,"name":"柿","price":60},{"id":4,"name":"キウイ","price":70},{"id":5,"name":"梨","price":120}]}
また、Type:"Lines" だと CSV 形式での出力も可能です。
取得用のスクリプト
準備については先日のブログエントリーを読んでください。 今回は「JSON Lines」に対して S3 Select を実行する python スクリプトを用意しました。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import boto3
s3 = boto3.client( 's3', 'ap-northeast-1' )
response_s3select = s3.select_object_content(
Bucket = 'sugano-test-2',
Key = 'test-data/price-list-1.json',
ExpressionType = 'SQL',
Expression = 'Select * from S3Object',
# Expression = 'Select s.id, s.name, s.price from S3Object s',
# Expression = 'Select count(*) as data_count from S3Object s',
# Expression = 'Select s.id, s.name, s.price from S3Object s where cast(s.id as int) > 3',
# Expression = 'Select sum(cast(s.price as int)) as price_sum from S3Object s',
# Expression = 'Select max(cast(s.price as int)) as price_max, cast(avg(cast(s.price as int)) as int) as price_ave, min(cast(s.price as int)) as price_min from S3Object s',
InputSerialization = {
'CompressionType': 'NONE',
'JSON' : {
'Type' : 'Lines'
}
},
OutputSerialization = {
'CSV' : {
'RecordDelimiter' : '\n',
'FieldDelimiter' : ','
}
}
# OutputSerialization = {
# 'JSON' : {
# 'RecordDelimiter' : '\n'
# }
# }
)
for event in response_s3select[ 'Payload' ]:
if 'Records' in event:
records = event[ 'Records' ][ 'Payload' ].decode( 'utf-8' )
print( records )
結果(CSV出力)
1,りんご,90
2,みかん,30
3,柿,60
4,キウイ,70
5,梨,120
JSON で出力する場合
ソースコードの中に JSON 形式で出力するための OutputSerialization もコメントアウトで埋めてあります。 以下のように CSV 用と切り替えてみましょう。
# OutputSerialization = {
# 'CSV' : {
# 'RecordDelimiter' : '\n',
# 'FieldDelimiter' : ','
# }
# }
OutputSerialization = {
'JSON' : {
'RecordDelimiter' : '\n'
}
}
結果は以下のようになります。
{"id":1,"name":"りんご","price":90}
{"id":2,"name":"みかん","price":30}
{"id":3,"name":"柿","price":60}
{"id":4,"name":"キウイ","price":70}
{"id":5,"name":"梨","price":120}
他の SQL 文も試してみる
- Select count(*) as data_count from S3Object s
{"data_count":5}
- Select s.id, s.name, s.price from S3Object s where cast(s.id as int) > 3
{"id":4,"name":"キウイ","price":70}
{"id":5,"name":"梨","price":120}
- Select sum(cast(s.price as int)) as price_sum from S3Object s
{"price_sum":370}
- Select max(cast(s.price as int)) as price_max, cast(avg(cast(s.price as int)) as int) as price_ave, min(cast(s.price as int)) as price_min from S3Object s
{"price_max":120,"price_ave":74,"price_min":30}
- 以下の SQL 文のように平均を int に cast していない場合は指数表記となるようです
- Select max(cast(s.price as int)) as price_max, avg(cast(s.price as int)) as price_ave, min(cast(s.price as int)) as price_min from S3Object s
{"price_max":120,"price_ave":74e0,"price_min":30}
まとめ
JSON Lines 形式のデータも、CSV 形式と同様に S3 Select で扱える事が確認できました。 Type:"Document" の場合の動作は 2018年4月27日現在だと残念な結果となりましたが、いつか改善されると思いますので待ちましょう。
さいごに
いかがでしたでしょうか。 少しのソース修正だけで JSON Lines 形式のデータに対応することができました。 本エントリーがを見た皆様が S3 Select を活用するための参考になれば幸いです。
参考ページ
以下のページを参考にさせていただきました。 ありがとうございました。 Amazon S3 Select および Amazon Glacier Select の SQL リファレンス - Amazon Simple Storage Service