チェックポイント
Create a new dataset and table to store the data
/ 20
Execute the query to see how many unique products were viewed
/ 15
Execute the query to use the UNNEST() on array field
/ 15
Create a dataset and a table to ingest JSON data
/ 20
Execute the query to COUNT how many racers were there in total
/ 10
Execute the query that will list the total race time for racers whose names begin with R
/ 10
Execute the query to see which runner ran fastest lap time
/ 10
BigQuery での JSON、配列、構造体の操作
GSP416
概要
BigQuery は、Google が低価格で提供する NoOps、フルマネージドの分析データベースです。BigQuery では、インフラストラクチャを所有して管理したりデータベース管理者を置いたりすることなく、テラバイト単位の大規模なデータでクエリを実行できます。また、SQL が採用されており、従量課金制というメリットもあります。このような特長を活かし、ユーザーは有用な情報を得るためのデータ分析に専念できます。
このラボでは、BigQuery での半構造化データの操作(JSON の取り込み、配列データ型)について詳しく学習します。スキーマを非正規化し、ネストされた繰り返しのフィールドを持つ単一のテーブルにすることで、パフォーマンスが改善する場合があります。ただし、配列データを操作する SQL 構文は複雑になることがあります。ここでは、さまざまな半構造化データセットに対する読み込み、クエリ実行、トラブルシューティング、ネスト解除を実際に行います。
演習内容
このラボでは、次の方法について学びます。
- ネスト解除を含む半構造化データの読み込みとクエリ実行を行う
- 半構造化データに対するクエリのトラブルシューティングを行う
設定と要件
[ラボを開始] ボタンをクリックする前に
こちらの手順をお読みください。ラボの時間は記録されており、一時停止することはできません。[ラボを開始] をクリックするとスタートするタイマーは、Google Cloud のリソースを利用できる時間を示しています。
このハンズオンラボでは、シミュレーションやデモ環境ではなく、実際のクラウド環境を使ってご自身でラボのアクティビティを行うことができます。そのため、ラボの受講中に Google Cloud にログインおよびアクセスするための、新しい一時的な認証情報が提供されます。
このラボを完了するためには、下記が必要です。
- 標準的なインターネット ブラウザ(Chrome を推奨)
- ラボを完了するために十分な時間を確保してください。ラボをいったん開始すると一時停止することはできません。
ラボを開始して Google Cloud コンソールにログインする方法
-
[ラボを開始] ボタンをクリックします。ラボの料金をお支払いいただく必要がある場合は、表示されるポップアップでお支払い方法を選択してください。 左側の [ラボの詳細] パネルには、以下が表示されます。
- [Google Cloud コンソールを開く] ボタン
- 残り時間
- このラボで使用する必要がある一時的な認証情報
- このラボを行うために必要なその他の情報(ある場合)
-
[Google Cloud コンソールを開く] をクリックします(Chrome ブラウザを使用している場合は、右クリックして [シークレット ウィンドウでリンクを開く] を選択します)。
ラボでリソースが起動し、別のタブで [ログイン] ページが表示されます。
ヒント: タブをそれぞれ別のウィンドウで開き、並べて表示しておきましょう。
注: [アカウントの選択] ダイアログが表示されたら、[別のアカウントを使用] をクリックします。 -
必要に応じて、下のユーザー名をコピーして、[ログイン] ダイアログに貼り付けます。
{{{user_0.username | "Username"}}} [ラボの詳細] パネルでも [ユーザー名] を確認できます。
-
[次へ] をクリックします。
-
以下のパスワードをコピーして、[ようこそ] ダイアログに貼り付けます。
{{{user_0.password | "Password"}}} [ラボの詳細] パネルでも [パスワード] を確認できます。
-
[次へ] をクリックします。
重要: ラボで提供された認証情報を使用する必要があります。Google Cloud アカウントの認証情報は使用しないでください。 注: このラボでご自身の Google Cloud アカウントを使用すると、追加料金が発生する場合があります。 -
その後次のように進みます。
- 利用規約に同意してください。
- 一時的なアカウントなので、復元オプションや 2 要素認証プロセスは設定しないでください。
- 無料トライアルには登録しないでください。
その後、このタブで Google Cloud コンソールが開きます。
BigQuery コンソールを開く
- Google Cloud コンソールで、ナビゲーション メニュー > [BigQuery] を選択します。
[Cloud コンソールの BigQuery へようこそ] メッセージ ボックスが開きます。このメッセージ ボックスには、クイックスタート ガイドとリリースノートへのリンクが表示されます。
- [完了] をクリックします。
BigQuery コンソールが開きます。
タスク 1. テーブルを保存するための新しいデータセットを作成する
- BigQuery で、プロジェクト ID の横にあるその他アイコンをクリックし、[データセットを作成] をクリックします。
-
新しいデータセットに「
fruit_store
」という名前を付けます。その他のオプション([データのロケーション]、[デフォルトのテーブルの有効期限])はデフォルト値のままにします。 -
[データセットを作成] をクリックします。
タスク 2. SQL での配列の操作を練習する
通常、SQL では、以下の果物リストのように各行に値が 1 つ含まれます。
行 |
果物 |
1 |
raspberry |
2 |
blackberry |
3 |
strawberry |
4 |
cherry |
果物リストに店舗の担当者名が必要な場合はどうすればよいでしょうか。次のようになります。
行 |
果物 |
担当者 |
1 |
raspberry |
sally |
2 |
blackberry |
sally |
3 |
strawberry |
sally |
4 |
cherry |
sally |
5 |
orange |
frederick |
6 |
apple |
frederick |
従来のリレーショナル データベースの SQL では、同じ名前が複数回出現する場合、上記のテーブルを果物と担当者の 2 つの別個のテーブルに分割することを考えます。これは正規化(1 つのテーブルを多数のテーブルに分割)と呼ばれ、mySQL のようなトランザクション データベースでよく行われます。
データ ウェアハウジングでよく行われるのはその逆の操作(非正規化)で、多数のテーブルを 1 つの大きなレポート テーブルにまとめます。
ここでは、繰り返しフィールドを使用して、粒度の異なるデータをすべて 1 つのテーブルに格納する方法を学びます。
行 |
果物(配列) |
担当者 |
1 |
raspberry |
sally |
blackberry | ||
strawberry | ||
cherry | ||
2 |
orange |
frederick |
apple |
上のテーブルの不自然な点はどこでしょうか。
- 行が 2 つだけである。
- [果物] 列では、1 つの行に複数のフィールド値がある。
- 担当者がすべてのフィールド値に関連付けられている。
ここからわかるのは、array
データ型が使用されているということです。
以下のように記述すると、果物の配列について理解しやすくなります。
行 |
果物(配列) |
担当者 |
1 |
[raspberry, blackberry, strawberry, cherry] |
sally |
2 |
[orange, apple] |
frederick |
これら両方のテーブルは同じ内容を表します。主な学習のポイントは 2 つあります。
- 配列は単純に [ ] で囲まれた項目のリストである
- BigQuery では配列が「フラット化」されて表示され、配列の値が単純に一列にリストされる(それでも、これらの値は 1 つの行に含まれています)
実際に試す
- BigQuery のクエリエディタに次のクエリを入力します。
-
[実行] をクリックします。
-
次のクエリを実行します。
次のようなエラーが表示されます。
Error: Array elements of types {INT64, STRING} do not have a common supertype at [3:1]
配列内では同じデータ型を使用する必要があります(すべて文字列、すべて数値など)。
- 最後に、テーブルに対して次のクエリを実行します。
-
[実行] をクリックします。
-
結果が表示されたら [JSON] タブをクリックして、ネストされた結果の構造を確認します。
半構造化 JSON を BigQuery に読み込む
BigQuery に JSON ファイルを取り込む必要がある場合はどうすればよいでしょうか。
データセット内に fruit_details
という新しいテーブルを作成します。
-
fruit_store
データセットをクリックします。
これで、[テーブルを作成] オプションが表示されます。
- 次のようにテーブルの詳細を設定します。
- [ソース]: [テーブルの作成元] プルダウンで [Google Cloud Storage] を選択します。
- [GCS バケットからファイルを選択]:
cloud-training/data-insights-course/labs/optimizing-for-performance/shopping_cart.json
- [ファイル形式]: JSONL(改行区切り JSON)
-
新しいテーブルの名前を「
fruit_details
」にします。 -
[スキーマ] セクションで [自動検出] チェックボックスをオンにします。
-
[テーブルを作成] をクリックします。
スキーマで fruit_array
が「REPEATED」に設定されているため、このフィールドが配列であることがわかります。
内容のまとめ
- BigQuery は配列をネイティブにサポートする
- 配列値のデータ型はすべて同じでなければならない
- BigQuery では配列を繰り返しフィールド(REPEATED)と呼ぶ
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
タスク 3. ARRAY_AGG() を使用して独自の配列を作成する
今度は配列を自分のテーブル内に作成しましょう。
- 以下のクエリをコピーして貼り付け、この一般公開データセットを探索します。
- [実行] をクリックして結果を確認します。
次に、ARRAY_AGG()
関数を使用して、これらの文字列値を 1 つの配列にまとめます。
- 以下のクエリをコピーして貼り付け、この一般公開データセットを探索します。
- [実行] をクリックして結果を確認します。
- 次に、
ARRAY_LENGTH()
関数を使用して、閲覧されたページと商品の数を調べます。
- ページと商品の重複を除去して、閲覧された一意の商品の数を調べます。そのためには
ARRAY_AGG()
にDISTINCT
を追加します。
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
内容のまとめ
次のように、配列に関連する便利な関数があります。
-
ARRAY_LENGTH(<array>)
で要素の数を調べる -
ARRAY_AGG(DISTINCT <field>)
で要素の重複を除去する -
ARRAY_AGG(<field> ORDER BY <field>)
で要素を並べ替える -
ARRAY_AGG(<field> LIMIT 5)
で要素の数を制限する
タスク 4. 配列を含むテーブルにクエリを実行する
Google アナリティクス向けの BigQuery 一般公開データセット bigquery-public-data.google_analytics_sample
には、このコースのデータセット data-to-insights.ecommerce.all_sessions
より多くのフィールドと行が含まれています。さらに重要な点として、商品、ページ、トランザクションなどのフィールド値が、配列としてネイティブに格納されています。
- 以下のクエリをコピーして貼り付け、どのようなデータがあるか調べます。繰り返し値(配列)を含むフィールドがないか探してみてください。
-
[実行] をクリックしてクエリを実行します。
-
結果を右にスクロールして、
hits.product.v2ProductName
フィールドを探します(複数フィールドのエイリアスについては、追って説明します)。
Google アナリティクス スキーマに含まれているフィールドは、ここで分析するには多すぎます。
- 前と同じように、訪問者とページ名のフィールドだけをクエリしてみましょう。
「Error: Cannot access field page on a value with type ARRAY<STRUCT<hitNumber INT64, time INT64, hour INT64, ...>> at [3:8]
」というエラーが表示されます。
繰り返しフィールド(配列)を通常どおりにクエリするには、まず配列を分割して複数の行に戻す必要があります。
たとえば、hits.page.pageTitle
の配列は、次のように 1 つの行として格納されています。
これを次のようにする必要があります。
これを SQL で行うにはどうすればよいでしょうか。
解答: 配列フィールドで UNNEST() 関数を使用します。
UNNEST() については後ほど詳しく説明します。ここでは差し当たり、次のことを覚えておいてください。
- 配列要素を行に戻すには UNNEST() を使用する
- UNNEST() は常に FROM 句のテーブル名の後に指定する(概念的には、事前に結合されたテーブルに似ています)
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
タスク 5. 構造体の概要
フィールド エイリアスである hit.page.pageTitle
について、3 つのフィールドをドットで区切って 1 つにまとめたように見えるのが気になった方もいらっしゃるでしょう。配列値を使用すると、フィールドの粒度をより細かく「掘り下げる」ことができますが、これと同様に、関連するフィールドをグループ化してスキーマを「広げる」ことができるデータ型があります。それが、SQL データ型の STRUCT(構造体)です。
概念的には、構造体はメインテーブルに事前に結合された別テーブルのようなものと考えるとわかりやすくなります。
構造体には次のような特徴があります。
- 1 つ以上のフィールドを含めることができる
- フィールドのデータ型は同じでなくてもよい
- 固有のエイリアスがある
このように、構造体はテーブルによく似ています。
構造体を含むデータセットを探索する
-
bigquery-public-data データセットを開くために [追加] をクリックして [名前を指定してプロジェクトにスターを付ける] を選択し、「
bigquery-public-data
」と入力します。 -
[スターを付ける] をクリックします。
bigquery-public-data
プロジェクトが [エクスプローラ] セクションに表示されます。
-
bigquery-public-data を開きます。
-
google_analytics_sample データセットを探して開きます。
-
ga_sessions(366)_ テーブルをクリックします。
-
スキーマをスクロールし、ブラウザの検索機能を使って次の質問に答えてください。
ご想像のとおり、昨今の e コマースサイトで格納されているウェブサイトのセッション データは膨大な量になります。
1 つのテーブルで 32 個もの構造体を使用する最大のメリットは、結合を一切行わずに次のようなクエリを実行できることです。
.*
という構文を使用すると、その構造体のすべてのフィールドが BigQuery から返されます(totals.*
で別のテーブルを結合した場合によく似ています)。大きなレポート テーブルを構造体(事前に結合された「テーブル」)や配列(粒度が細かい)として格納すると、次のようなメリットがあります。
- テーブルを 32 回も結合する必要がなくなるため、パフォーマンスが大幅に向上する
- 配列から必要に応じて細かい粒度でデータを取得でき、その必要がないときのデメリットもない(BigQuery では各列が個別にディスクに保存されます)
- すべてのビジネスデータが 1 つのテーブルに含まれるようになるため、結合キーに煩わされたり、必要なデータがどのテーブルにあるかを調べたりする必要がなくなる
タスク 6. 構造体と配列の使い方を練習する
次のデータセットは、トラックを走るランナーのラップタイムです。各ラップは「スプリット」と呼ばれます。
- このクエリで STRUCT 構文を試します。構造体コンテナ内には異なるフィールド タイプが混在する点に注意してください。
行 |
runner.name |
runner.split |
1 |
Rudisha |
23.4 |
フィールドのエイリアスについて、どのようなことがわかりますか。構造体内にネストされているフィールドがあるため(name と split が runner のサブセット)、ドットを使用して区切りが示されています。
1 つのレースでのランナーのスプリット タイムが複数ある場合はどうなるでしょうか(ラップごとのタイムなど)。
その場合は配列を使用します。
- 次のクエリを実行して確認します。
行 |
runner.name |
runner.splits |
1 |
Rudisha |
23.4 |
26.3 | ||
26.4 | ||
26.1 |
まとめると次のようになります。
- STRUCT は、ネストされた複数のフィールド名とデータ型を内部に保持できるコンテナです。
- 構造体内のフィールド タイプの一つに配列があります(上記の splits フィールドを参照)。
JSON データを実際に取り込む
-
「
racing
」という名前の新しいデータセットを作成します。 -
racing
データセットをクリックし、[テーブルを作成] をクリックします。
- [ソース]: [テーブルの作成元] プルダウン メニューから [Google Cloud Storage] を選択します。
- [GCS バケットからファイルを選択]:
cloud-training/data-insights-course/labs/optimizing-for-performance/race_results.json
- [ファイル形式]: JSONL(改行区切り JSON)
- [スキーマ] で [テキストとして編集] スライダーをオンにし、次の内容を追加します。
-
新しいテーブルの名前を「
race_results
」にします。 -
[テーブルを作成] をクリックします。
-
読み込みジョブが完了したら、新しく作成されたテーブルのスキーマをプレビューします。
構造体のフィールドはどれでしょうか。それを知る手掛かりは何ですか。
participants フィールドは RECORD 型なので構造体です。
配列のフィールドはどれでしょうか。
participants.splits
フィールドは、親である participants
構造体内の FLOAT の配列です。モードが REPEATED であるため、配列であることがわかります。この配列の値は、単一のフィールドに複数の値が含まれるため「ネストされた値」と呼ばれます。
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
ネストされた繰り返しフィールドに対してクエリを実行する
- 800 メートルレースのすべてのランナーを確認しましょう。
何件の行が返されましたか。
解答: 1
各ランナーの名前とレースの種類を一覧表示するにはどうすればよいでしょうか。
- 次のクエリを実行するとどうなるか確認しましょう。
Error: Cannot access field name on a value with type ARRAY<STRUCT<name STRING, splits ARRAY<FLOAT64>>>> at [2:27]
集計関数を使う際に GROUP BY を忘れた状態に似ています。ここでは、粒度の異なる 2 つの項目があります。レースが 1 行、参加者名が 3 行です。これをどのように変更すればよいでしょうか。
行 |
race |
participants.name |
1 |
800M |
Rudisha |
2 |
??? |
Makhloufi |
3 |
??? |
Murphy |
これを次のようにします。
行 |
race |
participants.name |
1 |
800M |
Rudisha |
2 |
800M |
Makhloufi |
3 |
800M |
Murphy |
従来のリレーショナル SQL では、レースのテーブルと参加者のテーブルがある場合、両方のテーブルから情報を取得するにはテーブルを結合する必要があります。ここでは、参加者の STRUCT(概念的にはテーブルによく似ています)は、すでにレースのテーブルには含まれていますが、STRUCT ではない「race」フィールドとはまだ適切に関連付けられていません。
最初のテーブルで 800M レースを各ランナーと関連付けるために使用する SQL コマンドは何ですか。
解答: CROSS JOIN
では、先に進みましょう。
- 次のクエリを実行します。
Table name "participants" missing dataset while no default dataset is set in the request
.
participants という構造体はテーブルに似ていますが、厳密に言えば racing.race_results
テーブル内のフィールドの一つです。
- クエリにデータセット名を追加します。
- 次に [実行] をクリックします。
この結果として、各レースのランナーがすべて一覧表示されました。
行 |
race |
name |
1 |
800M |
Rudisha |
2 |
800M |
Makhloufi |
3 |
800M |
Murphy |
4 |
800M |
Bosse |
5 |
800M |
Rotich |
6 |
800M |
Lewandowski |
7 |
800M |
Kipketer |
8 |
800M |
Berian |
- 以下の方法で最後のクエリを簡素化できます。
- 元のテーブルのエイリアスを追加する
- 「CROSS JOIN」の句をカンマで置き換える(カンマは暗黙的にクロス結合を表す)
これで同じクエリ結果が得られます。
レースの種類が複数ある場合(800M、100M、200M)、クロス結合では、デカルト積のように各ランナーの名前がすべてのレースと関連付けられることはないのでしょうか。
解答: そのようにはなりません。これは相関クロス結合であり、個々の行に関連付けられた要素のみが展開されます。詳しくは、ARRAY と STRUCT の操作をご参照ください。
STRUCT(構造体)のまとめ:
- SQL の STRUCT は、単純に他のデータ フィールド(データ型は異なっていても構いません)のコンテナです。構造体という言葉はデータが構造化されていることを表します。先ほどの例「
STRUCT(``"Rudisha" as name, [23.4, 26.3, 26.4, 26.1] as splits``)`` AS runner
」を思い出してください。 - 構造体にはエイリアス(上記の runner)が指定されます。概念的には、メインテーブル内に含まれるテーブルと考えることができます。
- STRUCT(および ARRAY)の要素を操作するには、事前にその STRUCT(および ARRAY)を展開する必要があります。構造体自体の名前または構造体に含まれる配列のフィールドを UNNEST() で囲み、展開してフラット化します。
タスク 7. ラボの質問: STRUCT()
先ほど作成した racing.race_results
テーブルを使用して以下の質問に解答してください。
タスク: 参加したランナーの合計数を取得するクエリを作成してください。
- まず、部分的に作成済みの次のクエリを使用します。
FROM
の後に追加のデータソースとして、構造体名でクロス結合する必要があります。解答例:
行 |
racer_count |
1 |
8 |
解答: レースに参加したランナーは 8 人です。
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
タスク 8. ラボの質問: 配列を UNNEST( ) で展開する
名前が「R」で始まるランナーの合計レース時間を一覧表示するクエリを作成します。合計時間が短いランナーが先に表示されるように並べ替えます。UNNEST() 演算子を使って、部分的に作成済みの次のクエリで作業を開始します。
- クエリを完成させてください。
- FROM 句の後に、構造体と構造体に含まれる配列の両方をデータソースとして展開する必要があります。
- 必要に応じてエイリアスを使用します。
解答例:
行 |
name |
total_race_time |
1 |
Rudisha |
102.19999999999999 |
2 |
Rotich |
103.6 |
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
タスク 9. 配列内の値でフィルタする
800M のレースで最も速いラップタイムは、23.2 秒でした。ただし、それがどのランナーの記録であるかは確認できていません。そこで、その結果を返すクエリを作成します。
- 部分的に作成済みの次のクエリを完成させてください。
解答例:
行 |
name |
split_time |
1 |
Kipketer |
23.2 |
[進行状況を確認] をクリックして、目標に沿って進んでいることを確認します。
お疲れさまでした
JSON データセットを取り込み、配列と構造体を作成し、半構造化データをネスト解除して分析情報を得ることができました。
次のステップと詳細情報
- 詳しくは、配列の操作をご覧ください。
- 以下のラボをご確認ください。
Google Cloud トレーニングと認定資格
Google Cloud トレーニングと認定資格を通して、Google Cloud 技術を最大限に活用できるようになります。必要な技術スキルとベスト プラクティスについて取り扱うクラスでは、学習を継続的に進めることができます。トレーニングは基礎レベルから上級レベルまであり、オンデマンド、ライブ、バーチャル参加など、多忙なスケジュールにも対応できるオプションが用意されています。認定資格を取得することで、Google Cloud テクノロジーに関するスキルと知識を証明できます。
マニュアルの最終更新日: 2024 年 2 月 3 日
ラボの最終テスト日: 2023 年 8 月 25 日
Copyright 2024 Google LLC All rights reserved. Google および Google のロゴは Google LLC の商標です。その他すべての企業名および商品名はそれぞれ各社の商標または登録商標です。