コンテンツに移動
データベース

Spanner の新しい JSON データ型でリレーショナル データのその先へ

2021年9月17日
https://storage.googleapis.com/gweb-cloudblog-publish/images/databases.max-2600x2600.jpg
Google Cloud Japan Team

※この投稿は米国時間 2021 年 9 月 3 日に、Google Cloud blog に投稿されたものの抄訳です。

JSON(JavaScript Object Notation)は、デベロッパーが階層データや半構造化データを扱う際に利用する形式です。JavaScript のサブセットである JSON は、ブラウザのリッチかつインタラクティブなエクスペリエンス、そして Node.js などのスクリプティング環境が爆発的に普及したことで人気を集めてきました。Cloud Spanner の新しい JSON データ型では、疎データやネストされたデータ、構造化が抑えられたデータを使ってリレーショナル データを拡張できます。Spanner ではアプリケーションが依存している可用性や一貫性を組織全体で犠牲にすることなく、高い柔軟性とアジリティが実現されます。

リレーショナルだけではもはや不十分

使い勝手の良さとリレーショナル データ モデルのパワーを兼ね備えているテクノロジーはほとんどありません。E. F. 当ブログの読者のなかで、Codd のオリジナルの論文をこれまでに読んだことのある方はいらっしゃるでしょうか。業務アプリケーションの構造化データをキャプチャする場合、通常はキーで関連付けられた行と列で構成されるテーブルを使用します。属性セットがそれぞれ適切に定義された「注文行」で構成される「販売注文」が「顧客」という項目にあるような場合がこれに当てはまります。しかし、今日のデータのなかにはテーブルでの厳密なモデリングに適していないものもあります。たとえば、3 つの異なるシステムから顧客データを取得し、システムごとに属性セットが異なっている、注文行の定義が頻繁に変わる、またはユーザーがその場で定義している場合はどうすればよいでしょうか。

何百種類もの商品を製造する大手電子機器メーカーがあり、商品ごとに属性のセットが異なると仮定してみましょう。ユーザーやアプリケーションが属性に対してクエリを実行する必要がない場合でも、属性のリレーショナル モデリングを行うには、新しい属性ごとにスキーマを変更する必要があります。成長中のビジネスや新製品がひっきりなしにオンラインに入ってくるなか、スキーマ変更の分析、モデリング、デプロイ、テストのサイクルがイノベーションの足かせになる場合もあります。この電子機器メーカーに本当に必要なのは、大半の商品に共通する、主要な属性の一貫性のあるセットに対してクエリを実行し、Spanner がもたらすトランザクションや豊富なクエリを完全に諦めることなく、他の大量の属性を簡単に管理できるようになることです。

構造や許容値に関する項目をあらかじめ定義することなく、Key-Value ペア(オブジェクト)、順序付きリスト(配列)、文字列、数値、ブール値を表すのに JSON は威力を発揮します。

今回の例の電子機器メーカーでは、次の(大幅に簡略化された)Products テーブルを使用して商品をモデリングします。

読み込んでいます...

これは属性を列に正規化する標準的なリレーショナル モデリングです。Spanner(またはすべてのリレーショナル データベース)では SQL を使用して、特定の列を基準にフィルタリングや集約を実行したり、他のテーブルに結合したりできます(注文行と商品の間に外部キーの関係がある場合など)。繰り返しになりますが、これこそがリレーショナル モデリングの基本です。

ただし、属性が商品ごとに大幅に異なる場合、列を使ったモデリングがやりにくくなります。数百万個ある商品のなかから 1 個にだけ SocketSize 属性が当てはまる場合もあります。

Spanner には、大量にある条件外の属性を JSON として保存するためのオプションがあります。厳密に型指定された列とは異なり、JSON 値では構造や値に関する項目をあらかじめ定義しておく必要がありません。そのため、リレーショナル スキーマを変更しなくても、簡単に新しい属性を追加できます。

読み込んでいます...

JSON はテーブル行の一部として保存されるため、JSON がすべての一貫性を保つとともに、Spanner で確実にクエリと更新を実行できるようにします。

他のテーブル同様、SQL を使用して、JSON データがあるテーブルに対してクエリを実行できます。ドット演算子(.)によって、JSON 値のプロパティに素早くアクセスできます。以下の例では、他の属性の socketSize プロパティを除外するために使用しています。

読み込んでいます...

また、JSONPath を使用して JSON 値を走査できる SQL 関数も Spanner には豊富に用意されています。

上記のクエリではリレーショナル モデルを使用して手間のかかるフィルタリングを処理しながら、フィルタリングしたセットの JSON 列を柔軟に除外できます。Spanner では、(現時点では)JSON 列のデータがインデックス処理されないため、この点は重要です。組み込みのクエリ オプティマイザーとインデックスでは明示的な列定義を利用しています。ただし、生成された列を使用することで、JSON 列から値を自動的に抽出して、それをインデックス処理やクエリに利用できます。生成された列は、依存する値と同じトランザクションで自動的に更新されるため、列とインデックスは常に最新の状態になります。

たとえば、今回の例の電子機器メーカーでは、商品カテゴリの分類をサブタイプでさらに改善することを検討しているとしましょう。一部の商品では、ExtendedAttributes のセットにサブタイプ プロパティがすでに追加されています。飛行機関連の商品に「aviation」というサブタイプがある場合、拡張属性を JSON で次のように表すことができます。

読み込んでいます...

SQL を使用することで、JSON 列に新しい行を挿入したり、既存の行を更新したりできます。

読み込んでいます...

有効な JSON であれば何でも JSON の値として使用できます。SQL では JSON を文字列として指定できますが、Spanner では内部的に効率の良い正規化表現を使用することで、ストレージ サイズを最小限に抑えてアクセスを高速化します。

今回のケースでは、JSON 列内からそれ自身の列に値をプロモートできます。その後、他の列と同じように、インデックスを作成してクエリを高速化できます。

読み込んでいます...

たとえば、サブタイプでフィルタリングするには次のようにします。

読み込んでいます...

このクエリでは ProductSubtypeIdx インデックスを使用することで、行ごとにスキャンされるのを回避しています。

Spanner の新しい JSON データ型では、リレーショナル テーブルに適さないデータをデベロッパーとデータ アーキテクトがこれまで以上に柔軟に管理できます。疎データや変化し続けるデータを処理する際にこれが威力を発揮します。組み込み関数が豊富に用意されているため、SQL を使用して JSON 列に対してクエリを実行できます。生成された列では、大規模なフィルタリング、結合、集約を行う必要がある場合に、JSON データから列に値を自動的に抽出できます。

-Cloud Spanner プロダクト マネージャー、Justin Makeig

-Cloud Spanner ソフトウェア エンジニア、Valentin Kuznetsov

投稿先