[新機能] Amazon Redshift 半構造化データをテーブルに直接保存できる新しいデータ型『SUPER』がGAになりました

2021.04.26

データアナリティクス事業本部コンサルティングチームの石川です。AWS re:Invent 2019で発表されたJSON や Nested Parquet などの半構造化データをローカルテーブルに直接取り込み、分析可能が可能になる新しいデータ型SUPERも遂にGA(Generally Available)になりました。早速試してみます。

半構造化データはSUPER型のカラムにそのまま格納し、SUPER型のデータとPartiQL言語を使用して、データウェアハウス機能を拡張し、SQLとNoSQLの両方のデータソースと統合します。このようにして、Redshiftは、JSONなどのリレーショナルおよび半構造化された保存データの効率的な分析を可能にします。

※ 以降の解説は、非構造化データはJSONを例に解説しますが、Nested Parquetでも基本的には同じ考えになります。

新しいデータ型『SUPER』とは

Redshiftのストレージに半構造化データのロードの課題

Redshiftのストレージに半構造化データ、例えばJSONファイルを読み込むには、別途マニフェスト作成して読み込む必要があり、更にNested JSONはサポートしていませんでした。そのため、Nested JSONファイルは事前にデータファイルをAWS Glue JobでETL(Relationalize)して、構造化データに変換した後、Redshiftに取り込む必要がありました。

半構造化データを直接保存できる新しいデータ型『SUPER』

データ型『SUPER』は、スキーマ定義を指定せずにJSONテキストをそのまま格納できます。そのため、データをロードする際にスキーマを意識することなくロードができて、クエリする際にJSONのキーを指定して値を取り出します。

つまり、スキーマをあまり理解していないJSONファイルを、まずはSUPER型のカラムに格納して、それから探索的にデータの中身を確認することができます。

また、スキーマレスであるということは、JSONのフォーマットに変更が生じたとしても、テーブル定義の変更は不要で、参照クエリを修正するだけで対応できます。

検証用サンプルデータ

用意したサンプルデータ(.json)は、jsonファイルから改行やインデントを取り除いたminify形式とprettify形式のデータを用意しました。

minify形式のサンプルデータ

{"r_regionkey":0,"r_comment":"lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to ","r_name":"AFRICA","r_nations":[{"n_comment":" haggle. carefully final deposits detect slyly agai","n_nationkey":0,"n_name":"ALGERIA"},{"n_comment":"ven packages wake quickly. regu","n_nationkey":5,"n_name":"ETHIOPIA"},{"n_comment":" pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t","n_nationkey":14,"n_name":"KENYA"},{"n_comment":"rns. blithely bold courts among the closely regular packages use furiously bold platelets?","n_nationkey":15,"n_name":"MOROCCO"},{"n_comment":"s. ironic, unusual asymptotes wake blithely r","n_nationkey":16,"n_name":"MOZAMBIQUE"}]}

prettify形式のサンプルデータ

{
  "r_regionkey": 0,
  "r_comment": "lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to ",
  "r_name": "AFRICA",
  "r_nations": [
    {
      "n_comment": " haggle. carefully final deposits detect slyly agai",
      "n_nationkey": 0,
      "n_name": "ALGERIA"
    },
    {
      "n_comment": "ven packages wake quickly. regu",
      "n_nationkey": 5,
      "n_name": "ETHIOPIA"
    },
    {
      "n_comment": " pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t",
      "n_nationkey": 14,
      "n_name": "KENYA"
    },
    {
      "n_comment": "rns. blithely bold courts among the closely regular packages use furiously bold platelets?",
      "n_nationkey": 15,
      "n_name": "MOROCCO"
    },
    {
      "n_comment": "s. ironic, unusual asymptotes wake blithely r",
      "n_nationkey": 16,
      "n_name": "MOZAMBIQUE"
    }
  ]
}

新しいデータ型『SUPER』を試してみる

SUPER型のテーブル作成

最初に、rdataというSUPER型のカラムを持つテーブルを作成します。データ型はSUPERと指定します。

cmdb=# CREATE TABLE region_nations_noshred (rdata SUPER);
CREATE TABLE

SUPER型のデータロード

単一のrdataというSUPER型のカラムにデータを取り込むには、FORMAT JSON句でnoshredオプションを指定します。

cmdb=# COPY region_nations_noshred
FROM 's3://cm-bucket/semistructured/tpch-nested/data/json/region_nation/'
REGION 'us-east-1'
IAM_ROLE 'arn:aws:iam::123456789012:role/cm-redshift-fullaccess-role'
FORMAT JSON 'noshred';
INFO:  Load into table 'region_nations_noshred' completed, 1 record(s) loaded successfully.
COPY

COPYコマンドでJSONを正常に取り込んだ後、region_nations_noshredテーブルには、単一のrdataというSUPER型のカラムにJSONオブジェクト全体のデータを含まれます。取り込んだデータは、JSON階層のすべてのプロパティを維持しますが、リーフは効率的なクエリ処理のためにAmazon Redshiftスカラータイプに変換されます。

実は、prettify形式のjsonファイルをロードしてもエラーにならず、minify形式に変換されてロードします。恐らく、jsonファイルをテキストで格納するのではなく、Amazon Redshiftスカラータイプに変換されるためではないかと考えられます。

SUPER型のカラムの参照

カラム名を指定すると、minify形式のデータがそのまま表示されます。

cmdb=# SELECT rdata FROM region_nations_noshred;
                                                                                                                                                                                                                                                                                                                                                                                      rdata
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 {"r_regionkey":0,"r_comment":"lar deposits. blithely final packages cajole. regular waters are final requests. regular accounts are according to ","r_name":"AFRICA","r_nations":[{"n_comment":" haggle. carefully final deposits detect slyly agai","n_nationkey":0,"n_name":"ALGERIA"},{"n_comment":"ven packages wake quickly. regu","n_nationkey":5,"n_name":"ETHIOPIA"},{"n_comment":" pending excuses haggle furiously deposits. pending, express pinto beans wake fluffily past t","n_nationkey":14,"n_name":"KENYA"},{"n_comment":"rns. blithely bold courts among the closely regular packages use furiously bold platelets?","n_nationkey":15,"n_name":"MOROCCO"},{"n_comment":"s. ironic, unusual asymptotes wake blithely r","n_nationkey":16,"n_name":"MOZAMBIQUE"}]}
(1 row)

SUPER型のカラムからキーを指定して値を取得する

キー名r_regionkeyを指定すると、値0が取れます。

cmdb=# SELECT rdata.r_regionkey FROM region_nations_noshred;
 r_regionkey
-------------
 0
(1 row)

SUPER型のカラムから配列の値を取得する

カラムに r_nations[0]を指定すると、r_nations[0]のjsonがそのまま取得できます。

cmdb=# SELECT rdata.r_nations[0] FROM region_nations_noshred;
                                               r_nations
--------------------------------------------------------------------------------------------------------
 {"n_comment":" haggle. carefully final deposits detect slyly agai","n_nationkey":0,"n_name":"ALGERIA"}
(1 row)

SUPER型のカラムからNested-JSONの値を取得する

カラムに r_nations[0].n_commentを指定すると、n_commentの値が取得できます。

cmdb=# SELECT rdata.r_nations[0].n_comment FROM region_nations_noshred;

                       n_comment
-------------------------------------------------------
 " haggle. carefully final deposits detect slyly agai"
(1 row)

SUPER型のユースケース

SUPERデータ型を使って半構造化データの取り込むと、使いやすく、優れたパフォーマンス、柔軟性が得られます。「使いやすく」と「柔軟性」はスキーマレスの特性であり、優れたパフォーマンスはリーフを効率的なクエリ処理のためにスカラータイプに変換して格納されるためです。

JSONデータの迅速かつ柔軟に取り込みしたい場合

Redshiftは、JSONを解析してSUPER型として保存できる高速なトランザクションをサポートしています。挿入トランザクションは、SUPERの属性を従来の列に細断処理したテーブルに同じ挿入を実行するよりも最大5倍高速に動作できます。

また、SUPER型は通常のスキーマを必要としません。JSONを保存するために、事前にデータ構造を確認してクリーンアップする必要はありません。クエリするときにデータを確認すればよいのです。

データ探索目的で柔軟にクエリしたい場合

半構造化データ(JSONなど)をSUPER型に格納した後、スキーマを課すことなくクエリを実行できます。PartiQL動的型付けと緩いセマンティクスを使用してクエリを実行し、クエリの前にスキーマ定義することなく、深くネストとされたデータを柔軟に探索できます。

ETL目的の簡単なクエリでマテリアライズドビューを作成したい場合

スキーマレスおよび半構造化データをSUPER型に格納した後、PartiQLマテリアライズドビューを使用して、データ構造を確認した後、マテリアライズドビューに共有できます。

非構造化データは、マテリアライズドビューでラップすることで、パフォーマンスと構造化された使いやすさの利点が得られます。特にBIツールとの連携では効果的です。

最後に

従来のRedshiftはキーバリュー形式のJSONサポートと比較して、SUPER型のJSONサポートーはNested-JSONもサポートしており、高速で柔軟です。SUPER型がスキーマレスであるということは、JSONのフォーマットに変更が生じたとしても、テーブル定義の変更は不要で、参照クエリを修正するだけで対応できます。また、JSONファイルの形式は、prettify形式とminify形式のどちらでもデータロード可能でした。

今後の非構造化データは、とりあえずSUPER型に取り込み、取り込んだあとに探索的にクエリを実行するのが標準的な使い方になると考えられます。