MusicBrainz データセットの使用
このチュートリアルでは、MusicBrainz データベース内のテーブルの JSON スナップショットを使用します。このデータベースは PostgreSQL で作成され、MusicBrainz の音楽に関する次のような情報が保存されています。
MusicBrainz スキーマには、artist、recording、artist_credit_name という 3 つの関連テーブルが定義されています。アーティストのクレジットは、レコーディングでアーティストに与えられたクレジットを表し、artist_credit_name 行は artist_credit 値でレコーディングとアーティストをリンクしています。
pg_cmd="\\copy (select row_to_json(r) from (select * from artist) r ) toexported_artist.json"psql -w -h $host -U $user -d $db -c $pg_cmdsed -i -e 's/\\\\/\\/g' exported_artist.json #clean up extra '\' characters
方法 1: BigQuery ウェブ UI で ETL を行う
この方法では、1 回に少量のデータを BigQuery に読み込み、分析を行います。サイズの大きいデータセットや複数のデータセットの自動処理を行う前に、データセットのプロトタイプを作成する場合にも使用します。
BigQuery データセットを作成する
次の図は、BigQuery データセットの作成手順を表しています。
MusicBrainz のテーブルを BigQuery に個別に読み込み、読み込まれたテーブルを結合します。各行には必要なデータリンクが含まれます。結合結果を新しい BigQuery テーブルに保存します。この処理が完了したら、読み込んだ元のテーブルを削除できます。
データセット名の右側にある下矢印ボタンをクリックします。
- [Create new dataset] をクリックします。
- [Create Dataset] ダイアログで、データセット ID と有効期限を追加して [OK] をクリックします。
MusicBrainz テーブルをインポートする
次の表に、このステップで使用する JSON ファイルの場所を示します。
| テーブル名 | スキーマ ファイル | データファイル |
|---|---|---|
| artist | https://storage.googleapis.com/solutions-public-assets/bqetl/artist_schema.json | gs://solutions-public-assets/bqetl/artist.json |
| artist_credit_name | https://storage.googleapis.com/solutions-public-assets/bqetl/artist_credit_name_schema.json | gs://solutions-public-assets/bqetl/artist_credit_name.json |
| recording | https://storage.googleapis.com/solutions-public-assets/bqetl/recording_schema.json | gs://solutions-public-assets/bqetl/recording.json |
各 MusicBrainz テーブルで、次の操作を行います。
- 上で作成したデータセットにテーブルを追加します。BigQuery 列のデータセット名にカーソルを合わせて、プラス記号をクリックします。
- [Create Table] ダイアログで、[Location] プルダウン リストから [Google Cloud Storage] を選択します。
- [Location] プルダウン リストの右側にあるテキスト フィールドに、データファイルの URL を入力します(例:
gs://solutions-public-assets/bqetl/artist.json)。 - [Table name] にテーブル名を入力します(例:
artist)。 - [File format] で [JSON(Newline Delimited)] を選択します。
- [Table type] で [Native table] を選択したままにします。
- [Schema] セクションで [Edit as Text] をクリックします。
- 上の表の URL を使用して、テーブルのスキーマをダウンロードします。
- ダウンロードしたスキーマ ファイルの内容で [Schema] セクションの内容を置き換えます。
- [Create Table] をクリックします。
データを非正規化する
データを非正規化するには、アーティストのレコーディングを 1 行とする新しい BigQuery テーブルにデータを結合し、分析用に特定のメタデータを使用します。
次のクエリをクエリのテキスト ボックスにコピーします。
SELECT artist.id, artist.gid, artist.name, artist.area, recording.name,recording.length, recording.gid, recording.video FROM[DATASET].artist as artist inner join[DATASET].artist_credit_name as artist_credit_name on artist.id= artist_credit_name.artist inner join [DATASET].recording asrecording on artist_credit_name.artist_credit = recording.artist_credit[DATASET] は、データセットの名前で置き換えます。
[Show Options] をクリックし、次のように選択します。
- [Table for Destination Table] を選択して、
recordings_by_artistsという名前で新しいテーブルを作成します。 - [Allow Large Results] をオンにします。
- [Write Preference] で [Overwrite table] を選択します。
- [Run Query] をクリックします。
- [Table for Destination Table] を選択して、
新しく作成した BigQuery テーブルでは、データがアーティストの曲ごとに編成されます。
方法 2: Cloud Dataflow で BigQuery に ETL を行う
このセクションでは、BigQuery ウェブ UI ではなく、サンプル プログラムを使用します。このプログラムでは、Cloud Dataflow パイプラインを使用してデータを BigQuery に読み込みます。次に、Cloud Dataflow プログラミング モデルを使用してデータの非正規化とクレンジングを行い、BigQuery に読み込みます。
始める前に、概念とサンプルコードを確認しておきましょう。
概念を確認する
ここで使用するデータはサイズが小さく、BigQuery ウェブ UI でも簡単に読み込むことができます。しかし、大規模な結合処理(500~5000 行で、10 TB を超えるデータ)の場合には、次の理由から BigQuery ウェブ UI ではなく Cloud Dataflow を使用して BigQuery に ETL を行います。
- BigQuery に読み込むときにデータをクレンジングできる。後で保存して結合する必要はありません(TB あたり $5 かかります)。また、ストレージ要件も低くなります。
- カスタムデータのクレンジングを行う。
- OLTP 以外のデータ(ログやリモートからアクセスするデータなど)とデータを組み合わせる。
- 継続的インテグレーションまたは継続的デプロイ(CI / CD)でデータの読み込みを自動化する。
- 段階的な繰り返しにより、ETL プロセスの強化 / 改善が期待できる。
- ETL を 1 回で行うのではなく、データを増分的に追加する。
次の図は、サンプル プログラムが作成するデータ パイプラインを表しています。
このサンプルコードでは、多くのパイプライン ステップがグループ化され、便利なメソッドでラッピングされています。わかりやすい名前が付いているので、再利用も簡単です。上の図で、再利用されるステップはダッシュで囲まれています。
パイプライン コードを確認する
このコードでは、次の操作を実行するパイプラインを作成します。
結合するテーブルを
PCollectionに読み込みます。各要素は、テーブル行の JSON 表現で構成されています。これらの JSON 文字列をオブジェクト表現(
MusicBrainzDataObjectオブジェクト)に変換し、列の値の 1 つ(主キーまたは外部キー)で編成します。artistテーブルとartist_credit_nameテーブルをMusicBrainzDataObjectオブジェクトのリストに変換したら、共通のアーティストで 2 つのリストを結合します。artist_credit_nameがアーティストのクレジットとレコーディングをリンクし、アーティストの外部キーが設定されます。artist_credit_nameテーブルがキー値KVオブジェクトのリストとして読み込まれます。K のメンバーがアーティストです。次のように、
MusicBrainzTransforms.innerJoin()メソッドでリストが結合されます。
MusicBrainzTransforms.innerJoin() メソッドは次のことを行います。
結合するキーメンバーで KV オブジェクトのコレクションをグループ化します。KV オブジェクトの
PCollectionに長整数型キー(artist.id列の値)が設定され、CoGbkResultが生成されます(キーの結果でグループが結合されていることを表します)。CoGbkResultオブジェクトは、最初と 2 番目のPCollectionsに共通のキー値を持つオブジェクト リストのタプルです。このタプルは、group by 演算の実行前に各PCollectionに構成されたタプルタグでアクセスできます。オブジェクトの一致を
MusicBrainzDataObjectオブジェクトにマージし、結合結果を表します。MusicBrainzDataObjectオブジェクト リストから構成されるリストが生成されます。各リストで、最初のテーブルにある一致の合計数に 2 番目のテーブルにある一致の合計数を掛けて特定のキー値が生成されます。複数リストが 1 つのPCollectionにフラット化され、複数のリストのMusicBrainzDataObjectオブジェクトがすべて含まれます。コレクションを KV オブジェクトのリストに編成し、次の結合を開始します。ここで、K 値は
artist_credit列で、recording テーブルとの結合に使用されます。MusicBrainzDataObjectオブジェクトの最終的なコレクションを取得します。この結果をartist_credit.idで編成された recordings のコレクションと結合します。結果の
MusicBrainzDataObjectsオブジェクトをTableRowsにマッピングします。結果のテーブルを BigQuery に書き込みます。
Cloud Dataflow パイプライン プログラミングの詳細については、プログラミング モデルに関する次のトピックをご覧ください。
コードの処理内容を確認したら、コードを実行しましょう。
パイプライン コードを実行する
作成したプロジェクトを使用するように gcloud SDK を設定します。
gcloud config set project [PROJECT]Cloud Dataflow コードを含むレポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/bigquery-etl-dataflow-sample.gitサンプルのあるディレクトリに移動します。
cd bigquery-etl-dataflow-sampleCloud Storage にステージング バケットを作成します。
gsutil mb gs://[STAGING_BUCKET_NAME][STAGING_BUCKET_NAME] のオブジェクト ライスサイクルに
dataflow-staging-policy.jsonの値を設定します。gsutil lifecycle set dataflow-staging-policy.json gs://[STAGING_BUCKET_NAME]このチュートリアルのサンプル スクリプトを編集します。このコードは、Maven を呼び出し、パイプラインを実行します。
run-simple.exampleファイルをrun-simpleという名前のファイルにコピーし、コードを変更してプロジェクトの名前、BigQuery データセット、宛先テーブルを設定します。結果が比較できるように、宛先テーブルには前のセクションと別のものを使用します。
このサンプルの Cloud Dataflow ジョブを実行します。
./run-simpleパイプラインでデータの書き込みが完了したら、次のスクリーンショットのように、新しいテーブルにクエリを実行します。
データをクレンジングする
次に、Cloud Dataflow パイプラインを少し変更します。次の図のように、ルックアップ テーブルを読み込み、副入力として処理します。
結果の BigQuery テーブルにクエリを実行する場合、アーティストの取得元を簡単に推測できません。MusicBrainz データベースでは、これは area になります。MusicBrainz データベースと同様に、結果の BigQuery テーブルでは area は ID で表示されます。これでクエリの結果を分析すると、上のクエリ結果のように簡単に分析を行うことができます。
同様に、アーティストの性別が ID で表されていますが、全体の MusicBrainz gender テーブルには 3 つの行しかありません。この問題を解決するため、MusicBrainz の area テーブルと gender テーブルを使用して、ID を正しいラベルにマッピングします。
artist_area と artist_gender は、アーティストやレコーディング データの量で制限がありませんが、それぞれ地理的なエリアや性別の制約を受けます。また、サイズも MB 単位の制約があります。この場合、副入力という Cloud Dataflow 機能を使用できます。
副入力は、行で区切りられた JSON 形式のテーブル エクスポートとして読み込まれます。
副入力をパイプラインに追加する
BQETLSimple.java ファイルには、いくつかのコメント行があります。
このコードは、副入力を使用してデータのクレンジングを行います。MusicBrainzTransforms クラスにより、副入力を使用して外部キーとラベルを簡単にマッピングできます。また、MusicBrainzTransforms ライブラリのメソッドを使用すると、内部ルックアップ クラスを作成できます。ルックアップ クラスは、ラベルと変数の長さ引数で置換されるルックアップ テーブルとフィールドを記述します。keyKey はルックアップ キーを含む列の名前です。valueKey は、対応するラベルを含む列の名前です。
それぞれの副入力は、1 つのマップ オブジェクトとして読み込まれ、ID に対応するラベルの検索に使用されます。
まず、ルックアップ テーブルの JSON が空の名前空間を持つ MusicBrainzDataObjects に読み込まれ、Key 列値から Value 列値のマップに変換されます。
これらの Map オブジェクトが destinationKey, の値で Map に読み込まれます。このキーは、検索された値で置き換わります。
JSON からアーティスト オブジェクトを変換するときに、destinationKey の値(数字で始まります)がラベルで置き換わります。
artist_area と artist_gender からデータをクリーンアップします。
BQETLSimple.javaで、ルックアップを使用してアーティストのデータを読み込む行のコメントを解除し、ルックアップを使用せずにアーティスト データを読み込むコードをコメントにします。対応する
intフィールドをコメントにし、対応するstringフィールドのコメントを解除して、artist_areaとartist_genderのTableFieldSchemasをintからstringに変更します。簡単なパイプライン コードを再度実行して、次のスクリーンショットのように、
artist_areaとartist_genderを含む同じクエリを実行します。
BigQuery スキーマを最適化する
次の図は、若干異なる Cloud Dataflow パイプラインを表しています。ここでは、重複するアーティスト行を作成するのではなく、アーティストのレコーディングをアーティスト行にネストします。
現在のデータ表現はかなりフラットです。クレジットのあるレコーディングごとに 1 つの行が存在し、BigQuery スキーマから取得したすべてのアーティスト メタデータを含みます。また、すべてのレコーディングと artist_credit_name メタデータも含まれています。このフラットな表現には、少なくとも 2 つの欠点があります。
- アーティストのレコーディングごとに
artistメタデータを繰り返すため、必要なストレージが増加します。 - データを JSON としてエクスポートすると、レコーディング データがネストされたアーティストではなく、このデータを繰り返す配列がエクスポートされます。おそらく、前者が必要なものです。
1 行に 1 つのレコーディングを保存するわけではないので、パフォーマンス上の問題はなく、追加のストレージも必要ありません。Cloud Dataflow パイプラインに簡単な変更を行うことで、アーティスト レコードの繰り返しフィールドとしてレコーディングを保存できます。
アーティスト情報とレコーディングを
artist_credit_name.artistで結合せずに、パイプラインがレコーディングのリストを作成し、アーティスト オブジェクト内にネストします。TableRowは、BigQuery API でサイズ制限があります。1 つのレコードにネストできるレコーディングは 1,000 要素に制限されています。特定のアーティストに 1,000 を超えるレコーディングが存在すると、コードがartistメタデータを含む行を複製し、複製した行にレコーディング データのネストを行います。run-nested.exampleスクリプトを./run-nestedにコピーし、設定に一致するように#PROJECT、#STAGING_BUCKET、#DATASET、#DESTINATION_TABLEを変更します。パイプラインを実行して、アーティスト行内にレコーディング行をネストします。
./run-nested