Bigtable にデータをエクスポートする(リバース ETL)

このドキュメントでは、BigQuery から Bigtable へのリバース ETL(RETL)を設定する方法について説明します。これを行うには、EXPORT DATA ステートメントを使用して、BigQuery テーブルから Bigtable テーブルにデータをエクスポートします。

Bigtable への RETL ワークフローを使用すると、Bigtable の低レイテンシと高スループットを BigQuery の分析機能に組み合わせることができます。このワークフローでは、BigQuery の割り当てと上限を使い切ることなく、アプリケーション ユーザーにデータを配信できます。

Bigtable テーブルの特性

Bigtable テーブルは、いくつかの点で BigQuery テーブルと異なります。

  • Bigtable テーブルと BigQuery テーブルはどちらも行で構成されていますが、Bigtable の行は、同じ列ファミリーに属する任意の数の列を持つ行キーと列ファミリーで構成されます。
  • 特定のテーブルの列ファミリーはテーブルの作成時に作成されますが、後で追加または削除することもできます。列ファミリーを作成するときに、それに属する列を指定する必要はありません。
  • Bigtable の列は事前に定義する必要はありません。テーブルのデータサイズの制限内の名前(修飾子)でデータを保存するために使用できます。
  • Bigtable の列には、テーブルのデータサイズの上限内の任意のバイナリ値を設定できます。
  • Bigtable の列には、常に時間ディメンション(バージョン)があります。タイムスタンプが同一でない限り、同じ列に任意の数の値を格納できます。
  • Bigtable のタイムスタンプは、Unix エポック時刻からのマイクロ秒単位で測定されます。たとえば、0 は 1970-01-01T00:00:00 UTC を表します。タイムスタンプは、ミリ秒単位の粒度で、負ではないマイクロ秒単位にする必要があります(1,000 マイクロ秒の倍数のみを使用できます)。Bigtable のデフォルトのタイムスタンプは 0 です。
  • Bigtable 内のデータは、行キー、複数の行キー、行キーの範囲、またはフィルタによって読み取られます。テーブル全体のスキャンを除くどのタイプの読み取りリクエストでも、1 つ以上の行キーまたは行キー範囲が必要です。

Bigtable にエクスポートする BigQuery の結果を準備する方法については、エクスポートするクエリ結果を準備するをご覧ください。

始める前に

エクスポートされたデータを受け取るには、Bigtable インスタンスBigtable テーブルを作成する必要があります。

このドキュメントの各タスクを実行するために必要な権限をユーザーに与える Identity and Access Management(IAM)のロールを付与します。

必要なロール

BigQuery データを Bigtable にエクスポートするために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

制限事項

ロケーションに関する留意事項

  • BigQuery データセットがマルチリージョンにある場合は、そのマルチリージョン内の Bigtable クラスタにデータを転送するように Bigtable アプリ プロファイルを構成する必要があります。たとえば、BigQuery データセットが US マルチリージョンにある場合、Bigtable クラスタは米国内の us-west1(オレゴン)リージョンに配置できます。
  • BigQuery データセットが単一リージョンにある場合は、同じリージョンの Bigtable クラスタにデータを転送するように Bigtable アプリ プロファイルを構成する必要があります。たとえば、BigQuery データセットが asia-northeast1(東京)リージョンにある場合、Bigtable クラスタも asia-northeast1(東京)リージョンに配置する必要があります。

詳細については、Bigtable のロケーションをご覧ください。

サポートされている BigQuery の型

Bigtable に書き込まれるデータの種類は次のとおりです。

BigQuery の型 書き込まれる Bigtable の値
BYTES そのままエクスポートされます。
STRING BYTES に変換されます。
INTEGER bigtable_options.column_families.encodingBINARY に設定されている場合、値は 8 バイトのビッグ エンディアン形式(最上位バイトが最初)で書き込まれます。bigtable_options.column_families.encodingTEXT に設定されている場合、値は数値を表す文字列として人が読める形式で書き込まれます。
FLOAT IEEE 754 の 8 バイトの出力形式で値を書き込みます。
BOOLEAN bigtable_options.column_families.encodingBINARY に設定されている場合、値は 1 バイトの値として書き込まれます(false = 0x00 または true = 0x01)。bigtable_options.column_families.encodingTEXT に設定されている場合、値はテキスト("true" または "false")として書き込まれます。
JSON
エクスポートされた JSON 型の列は、特定の Bigtable 列ファミリーに属する列のグループとして解釈されます。JSON オブジェクトのメンバーは列として解釈され、その値は Bigtable に書き込まれます。書き込まれる列の名前は、bigtable_options 構成で調整できます。

例:
    JSON '{"FIELD1": "VALUE1", "FIELD2": "VALUE2"}' as MY_COLUMN_FAMILY
    
ここで、値 VALUE1VALUE2 は列 FIELD1 および FIELD2 として Bigtable の列ファミリー MY_COLUMN_FAMILY に書き込まれます。
STRUCT
エクスポートされた STRUCT 型の列は、特定の Bigtable 列ファミリーに属する列のグループとして解釈されます。構造体のメンバーは列として解釈され、その値は Bigtable に書き込まれます。書き込まれる列の名前は、bigtable_options 構成で調整できます。

例:
    STRUCT<FIELD1  STRING, FIELD2 INTEGER> as MY_COLUMN_FAMILY
    
ここで、値 FIELD1FIELD2 は列 FIELD1 および FIELD2 として Bigtable の列ファミリー MY_COLUMN_FAMILY に書き込まれます。

これらのサポートされるデータ型は、BigQuery の外部 Bigtable テーブルからの読み取りに似ています。

Bigtable 内の NULL

Bigtable の NULL 値には次の制約があります。

  • Bigtable には NULL 値に類似する値がありません。Bigtable で特定の列ファミリーと列の NULL 値をエクスポートすると、Bigtable の行から現在の値が削除されます。

  • エクスポート前に特定の行キー、列ファミリー、列修飾子、タイムスタンプを持つ Bigtable 値が存在しない場合、エクスポートされた NULL 値は Bigtable 行に影響しません。

  • STRUCT 型または JSON 型の NULL 値をエクスポートすると、影響を受ける行が対応する列ファミリーの列値がすべて削除されます。SQL エンジンが適切なタイプに接続できるように、NULL 値を STRUCT 型または JSON 型にキャストする必要があります。次のクエリは、指定された行キーのセットを持つ列ファミリー column_family1 からすべてのデータを削除します。

    EXPORT DATA OPTIONS (...) AS
    SELECT
      rowkey,
    CAST(NULL as STRUCT<INT64>) AS column_family1 FROM T
  • 行キーが NULL の行はエクスポート時にスキップされます。スキップされた行数は、エクスポート統計情報で呼び出し元に返されます。

bigtable_options を使用してエクスポートを構成する

エクスポート時に bigtable_options 構成を使用して、BigQuery と Bigtable のストレージ モデルの違いを埋めることができます。構成は、次の例のように JSON 文字列の形式で表現されます。

EXPORT DATA OPTIONS(
   uri="https://bigtable.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/appProfiles/APP_PROFILE_ID/tables/TABLE",
   bigtable_options = """{
     "columnFamilies": [{
       "familyId": "COLUMN_FAMILY_NAME",
       "encoding": "ENCODING_VALUE",
       "columns": [
         {
           "qualifierString": "BIGTABLE_COLUMN_QUALIFIER",
           ["qualifierEncoded": "BASE_64_ENCODED_VALUE",]
           "fieldName": "BIGQUERY_RESULT_FIELD_NAME"
         }
       ]
    }]
   }"""
)

次の表に、bigtable_options 構成で使用される可能性のあるフィールドを示します。

フィールド名 説明
columnFamilies 列ファミリー記述子の配列。
columnFamilies.familyId Bigtable の列ファミリーの識別子。
columnFamilies.encoding 値は BINARY または TEXT に設定できます。型のエンコード方法については、サポートされている BigQuery の型をご覧ください。
columnFamilies.columns Bigtable の列マッピングの配列。
columnFamilies.columns.qualifierString 省略可: Bigtable の列修飾子。列修飾子に UTF-8 以外のコードがない場合は、この値を指定します。フィールド qualifierStringqualifierEncoding は相互に排他的です。qualifierStringqualifierEncoded のどちらも指定されていない場合は、fieldName が列修飾子として使用されます。
columnFamilies.columns.qualifierEncoded 省略可: Base64 でエンコードされた列修飾子。列修飾子に UTF-8 以外のコードを含める必要がある場合の qualifierString と同様です。
columnFamilies.columns.fieldName 必須: BigQuery 結果セットのフィールド名。状況によっては空の文字列にすることもできます。空の fieldName 値を単純な型のフィールドで使用する方法については、エクスポートするクエリ結果を準備するをご覧ください。

エクスポートするクエリ結果を準備する

クエリ結果を Bigtable にエクスポートするには、結果が次の要件を満たしている必要があります。

  • 結果セットに STRING 型または BYTES 型の列 rowkey が含まれている必要があります。
  • 行キー、列修飾子、値、タイムスタンプは、Bigtable のテーブル内のデータサイズの上限を超えないようにする必要があります。
  • 結果セットには、rowkey 以外の列が少なくとも 1 つ必要です。
  • 各結果セットの列は、サポートされる BigQuery の型のいずれかである必要があります。サポートされていない列の型は、Bigtable にエクスポートする前に、サポートされている型のいずれかに変換する必要があります。

Bigtable では、有効な BigQuery 列名として列修飾子は必要ありません。また、任意のバイトの使用がサポートされています。エクスポートのターゲット列修飾子をオーバーライドする方法については、bigtable_options を使用してエクスポートを構成するをご覧ください。

エクスポートされた値を Bigtable API(ReadModifyWriteRow など)で使用する場合は、数値に正しいバイナリ エンコードを使用する必要があります。

デフォルトでは、STRUCT または JSON 以外の型のスタンドアロンの結果列は、宛先列ファミリーの値が結果列名に等しく、列修飾子が空の文字列に等しい値として解釈されます。

これらのデータ型がどのように記述されるかを説明するために、次の SQL の例で考えてみましょう。ここで、columncolumn2 はスタンドアロンの結果列です。

SELECT
  x as column1, y as column2
FROM table

このクエリ例では、JSON または STRUCT 以外の型を処理するときに、SELECT x as column1 は Bigtable の column1 列ファミリーと ''(空の文字列)列修飾子の下に値を書き込みます。

次の例に示すように bigtable_options 構成を使用すると、これらの型がエクスポートに書き込まれる方法を変更できます。

EXPORT DATA OPTIONS (
  
  bigtable_options="""{
   "columnFamilies" : [
      {
        "familyId": "ordered_at",
        "columns": [
           {"qualifierString": "order_time", "fieldName": ""}
        ]
      }
   ]
}"""
) AS
SELECT
  order_id as rowkey,
  STRUCT(product, amount) AS sales_info,
  EXTRACT (MILLISECOND FROM order_timestamp AT TIME ZONE "UTC") AS ordered_at
FROM T

この例では、BigQuery テーブル T に次の行が含まれています。

order_id order_timestamp product amount
101 2023-03-28T10:40:54Z ジョイスティック 2

上記の bigtable_options 構成をテーブル T で使用すると、次のデータが Bigtable に書き込まれます。

rowkey sales_info(列ファミリー) ordered_at(列ファミリー)
101 product amount order_time
1970-01-01T00:00:00Z ジョイスティック 1970-01-01T00:00:00Z 2 1680000054000

1680000054000 は、2023-03-28T10:40:54Z を UTC タイムゾーンの Unix エポック時刻からのミリ秒単位で表します。

_CHANGE_TIMESTAMP を使用して行内のすべてのセルにタイムスタンプを設定する

結果に TIMESTAMP 型の _CHANGE_TIMESTAMP 列を追加してエクスポートできます。Bigtable に書き込まれるすべてのセルでは、エクスポートされた結果行の _CHANGE_TIMESTAMP のタイムスタンプ値が使用されます。

Bigtable は、Unix エポック(1970-01-01T00:00:00Z)より前のタイムスタンプをサポートしていません。_CHANGE_TIMESTAMP の値が NULL の場合、デフォルトのタイムスタンプ値として Unix エポック時刻 0 が使用されます。

次のクエリは、テーブル Torder_timestamp 列で指定されたタイムスタンプを使用して product 列と amount 列のセルを書き込みます。

EXPORT DATA OPTIONS (...) AS
SELECT
  rowkey,
  STRUCT(product, amount) AS sales_info,
  order_timestamp as _CHANGE_TIMESTAMP
FROM T

継続的にエクスポートする

エクスポート クエリを継続的に処理する場合は、継続的クエリとして構成できます。

同じ rowkey 値を含む複数の結果をエクスポートする

同じ rowkey 値を持つ複数の行を含む結果をエクスポートすると、Bigtable に書き込まれた値は同じ Bigtable 行に格納されます。

この方法を使用すると、同じ行の列値の複数のバージョンを生成できます。この例では、BigQuery の orders テーブルに次のデータが含まれています。

id customer order_timestamp amount_spent
100 Bob 2023-01-01T10:10:54Z 10.99
101 Alice 2023-01-02T12:10:50Z 102.7
102 Bob 2023-01-04T15:17:01Z 11.1

次に、ユーザーが次の EXPORT DATA ステートメントを実行します。

EXPORT DATA OPTIONS (
uri="https://bigtable.googleapis.com/projects/PROJECT-ID/instances/INSTANCE-ID/appProfiles/APP_PROFILE_ID/tables/TABLE",
format="CLOUD_BIGTABLE"
) AS
SELECT customer as rowkey, STRUCT(amount_spent) as orders_column_family, order_timestamp as _CHANGE_TIMESTAMP
FROM orders

このステートメントを BigQuery orders テーブルで使用すると、次のデータが Bigtable に書き込まれます。

orders_column_family
行キー amount_spent
Alice 2023-01-02T12:10:50Z 102.7
Bob 2023-01-01T10:10:54Z 10.99
2023-01-04T15:17:01Z 11.1

Bigtable にエクスポートすると、行全体を置き換えるのではなく、新しい値がテーブルにマージされます。Bigtable に行キーの値がすでに存在する場合は、列ファミリー、列名、書き込まれるセルのタイムスタンプに応じて、以前の値を新しい値で部分的または完全にオーバーライドできます。

複数の列をプロトコル バッファ(Protobuf)の値としてエクスポートする

プロトコル バッファは、構造化データをシリアル化するための柔軟で効率的なメカニズムを提供します。Protobuf としてエクスポートすることは、BigQuery と Bigtable の間で異なる型を処理する方法に比べると便利です。BigQuery のユーザー定義関数(UDF)を使用すると、データを Protobuf バイナリ値として Bigtable にエクスポートできます。詳細については、Protobuf 列としてデータをエクスポートするをご覧ください。

エクスポートの最適化

Bigtable 宛先クラスタのノード数を変更すると、BigQuery から Bigtable にレコードをエクスポートする場合のスループットを変更できます。スループット(1 秒あたりに書き込まれる行数)は、宛先クラスタ内のノード数に比例してスケーリングされます。たとえば、宛先クラスタ内のノードの数を 2 倍にすると、エクスポート スループットがほぼ 2 倍になります。

料金

標準クエリでデータをエクスポートする場合は、データ抽出の料金に基づいて課金されます。継続的クエリでデータをエクスポートする場合は、BigQuery 容量コンピューティングの料金が適用されます。継続的クエリを実行するには、Enterprise エディションまたは Enterprise Plus エディションを使用する予約と、CONTINUOUS ジョブタイプを使用する予約の割り当てが必要です。

データのエクスポート後、Bigtable にデータを保存すると料金が発生します。詳細については、Bigtable の料金をご覧ください。