パーティション分割テーブルデータの管理

このドキュメントでは、BigQuery でパーティション分割テーブルデータを管理する方法について説明します。分割テーブルデータには、次の操作ができます。

  • 分割テーブルへのデータの読み込み
  • パーティション分割テーブルデータの閲覧(またはプレビュー)
  • パーティション分割テーブルデータのクエリ
  • パーティション分割テーブルデータの追加または上書き
  • データ操作言語のステートメントを使用したパーティション分割テーブルデータの変更
  • パーティション分割テーブルデータのコピー
  • パーティション分割テーブルへのデータのストリーミング
  • パーティション分割テーブルデータのエクスポート

テーブル スキーマの管理については、テーブル スキーマの変更をご覧ください。

パーティション分割テーブルへのデータの読み込み

データを読み込むときにパーティション分割テーブルを作成することも、空のパーティション分割テーブルを作成して、後でデータを読み込むこともできます。パーティション分割テーブルにデータを読み込むときに、サポートされているデータ形式であれば、スキーマの自動検出を使用できます。また、スキーマを指定することもできます。

パーティション分割テーブルにデータを読み込むときにスキーマの自動検出を使用するには、Cloud Console、bq コマンドライン ツールまたは API を使用します。

データの読み込みの詳細については、ソースデータの形式とロケーションに関するドキュメントをご覧ください。

Java

このサンプルを試す前に、BigQuery クイックスタート: クライアント ライブラリの使用の Java の設定手順を実施してください。詳細については、BigQuery Java API のリファレンス ドキュメントをご覧ください。

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.Field;
import com.google.cloud.bigquery.FormatOptions;
import com.google.cloud.bigquery.Job;
import com.google.cloud.bigquery.JobId;
import com.google.cloud.bigquery.JobInfo;
import com.google.cloud.bigquery.LoadJobConfiguration;
import com.google.cloud.bigquery.Schema;
import com.google.cloud.bigquery.StandardSQLTypeName;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TimePartitioning;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.UUID;

public class LoadPartitionedTable {

  public static void runLoadPartitionedTable() throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String sourceUri = "/path/to/file.csv";
    loadPartitionedTable(datasetName, tableName, sourceUri);
  }

  public static void loadPartitionedTable(String datasetName, String tableName, String sourceUri)
      throws Exception {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      TableId tableId = TableId.of(datasetName, tableName);

      Schema schema =
          Schema.of(
              Field.of("name", StandardSQLTypeName.STRING),
              Field.of("post_abbr", StandardSQLTypeName.STRING),
              Field.of("date", StandardSQLTypeName.DATE));

      // Configure time partitioning. For full list of options, see:
      // https://cloud.google.com/bigquery/docs/reference/rest/v2/tables#TimePartitioning
      TimePartitioning partitioning =
          TimePartitioning.newBuilder(TimePartitioning.Type.DAY)
              .setField("date")
              .setExpirationMs(Duration.of(90, ChronoUnit.DAYS).toMillis())
              .build();

      LoadJobConfiguration loadJobConfig =
          LoadJobConfiguration.builder(tableId, sourceUri)
              .setFormatOptions(FormatOptions.csv())
              .setSchema(schema)
              .setTimePartitioning(partitioning)
              .build();

      // Create a job ID so that we can safely retry.
      JobId jobId = JobId.of(UUID.randomUUID().toString());
      Job loadJob = bigquery.create(JobInfo.newBuilder(loadJobConfig).setJobId(jobId).build());

      // Load data from a GCS parquet file into the table
      // Blocks until this load table job completes its execution, either failing or succeeding.
      Job completedJob = loadJob.waitFor();

      // Check for errors
      if (completedJob == null) {
        throw new Exception("Job not executed since it no longer exists.");
      } else if (completedJob.getStatus().getError() != null) {
        // You can also look at queryJob.getStatus().getExecutionErrors() for all
        // errors, not just the latest one.
        throw new Exception(
            "BigQuery was unable to load into the table due to an error: \n"
                + loadJob.getStatus().getError());
      }
      System.out.println("Data successfully loaded into time partitioned table during load job");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println(
          "Data not loaded into time partitioned table during load job \n" + e.toString());
    }
  }
}

テーブルデータの閲覧

パーティション分割テーブルのデータは、次の方法で参照できます。

  • Cloud Console を使用する
  • bq コマンドライン ツールの bq head コマンドを使用する
  • tabledata.list API メソッドを呼び出す
  • クライアント ライブラリを使用する

必要な権限

テーブルとパーティションのデータを閲覧するには、少なくとも bigquery.tables.getData 権限が付与されている必要があります。次の事前定義済みの IAM ロールには bigquery.tables.getData 権限が含まれています。

  • bigquery.dataViewer
  • bigquery.dataEditor
  • bigquery.dataOwner
  • bigquery.admin

また、bigquery.datasets.create 権限を持つユーザーがデータセットを作成すると、そのデータセットに対する bigquery.dataOwner アクセス権がユーザーに付与されます。bigquery.dataOwner アクセス権により、ユーザーはデータセットに含まれるテーブルとパーティションのデータを閲覧できます。

BigQuery での IAM のロールと権限について詳しくは、事前定義されたロールと権限をご覧ください。

パーティション分割テーブルデータの閲覧

パーティション分割テーブルデータを閲覧するには:

Console

  1. Cloud Console のナビゲーション パネルで、データセットをクリックしてテーブルとビューを一覧表示します。

  2. リスト内のパーティション分割テーブルをクリックします。

  3. [詳細] タブをクリックします。

    テーブルの詳細

  4. [行数] の値を書き留めます。API または bq コマンドライン ツールを使用して結果の開始点を制御するために、この値が必要になることがあります。

    行数

  5. [プレビュー] タブをクリックします。データのサンプルセットが表示されます。Cloud Console を使用して個々のパーティションをプレビューすることはできません。

bq

--max_rows フラグを指定して bq head コマンドを発行すると、特定の数のテーブル行のすべてのフィールドが一覧表示されます。--max_rows が指定されていない場合、デフォルトは 100 です。パーティション デコレータ(例: $20180224)を使用して閲覧するパーティションを指定します。

bq head コマンドはクエリジョブを作成しないため、クエリ履歴には bq head コマンドは示されません。また、このコマンドに対して料金は発生しません。

テーブル内のフィールドのサブセット(ネスト フィールドと繰り返しフィールドを含む)を閲覧するには、--selected_fields フラグを使用して、フィールドをカンマ区切りのリストとして入力します。

テーブルデータを表示する前にスキップする行数を指定するには、--start_row=integer フラグ(または -s ショートカット)を使用します。デフォルト値は 0 です。テーブルの行数を取得するには、bq show コマンドを使用してテーブル情報を取得します。

閲覧しているテーブルがデフォルトのプロジェクト以外のプロジェクトにある場合は、project_id:dataset.table の形式でプロジェクト ID をコマンドに追加します。

bq head \
--max_rows integer1 \
--start_row integer2 \
--selected_fields "fields" \
project_id:dataset.table$partition

ここで

  • integer1 は、表示する行数です。
  • integer2 は、データを表示する前にスキップする行数です。
  • fields は、フィールドのカンマ区切りのリストです。
  • project_id は、プロジェクト ID です。
  • dataset は、テーブルを含むデータセットの名前です。
  • table は、閲覧するテーブルの名前です。
  • $partition は、パーティション デコレータです。

例:

"2018-02-24" パーティションの mydataset.mytable の最初の 10 行の項目をすべて一覧表示するには、次のコマンドを入力します。mydataset はデフォルト プロジェクトにあります。

bq head --max_rows=10 'mydataset.mytable$20180224'

"2016-09-01" パーティションの mydataset.mytable の最初の 100 行の項目をすべて一覧表示するには、次のコマンドを入力します。出力は JSON 形式で記述されます。この例では、デフォルトのプロジェクトを使用する代わりに、プロジェクトとして myotherproject を指定しています。

bq head --format=prettyjson 'myotherproject:mydataset.mytable$20160901'

"2016-09-01" パーティション内の mydataset.mytablefield1field2 のみを表示するには、次のコマンドを入力します。このコマンドでは --start_row フラグを使用して 100 行目にスキップしています。mydataset.mytable はデフォルト プロジェクトにあります。

bq head \
--format=prettyjson \
--start_row 100 \
--selected_fields "field1,field2" \
'mydataset.mytable$20160901'

API

tabledata.list を呼び出して、テーブルのデータを閲覧します。tableId パラメータでテーブルの名前とパーティション デコレータを指定します。

次のオプション パラメータを構成して出力を制御します。

  • maxResults - 返される結果の最大数。
  • selectedFields - 返されるフィールドのカンマ区切りリスト(指定しなかった場合、すべてのフィールドが返されます)
  • startIndex - 読み取りを開始する行を指し示す、ゼロから始まるインデックス。

値は 1 つの JSON オブジェクトにラップされて返されます。このオブジェクトを、tabledata.list リファレンス ドキュメントに記載されている手順に沿って解析する必要があります。

パーティション分割テーブルデータのクエリ

BigQuery にデータを読み込んだ後に、テーブル内のデータをクエリで取得できます。BigQuery は次の 2 種類のクエリをサポートします。

デフォルトで、BigQuery はインタラクティブ クエリを実行します。つまり、クエリはすぐに実行されます。

BigQuery ではバッチクエリも提供されています。BigQuery はユーザーに代わって各バッチクエリをキューに格納し、アイドル状態のリソースが使用可能になると直ちに(通常は数分以内に)クエリを開始します。

以下を使用して、インタラクティブ クエリとバッチクエリを実行できます。

詳細については、パーティション分割テーブルのクエリをご覧ください。

パーティション分割テーブルデータの追加と上書き

読み込みまたはクエリ オペレーションを使用してパーティション分割テーブルデータを上書きできます。既存のパーティション分割テーブルにデータを追加するには、読み込み追加オペレーションを実行するか、クエリ結果を追加します。このセクションのオペレーションは、日次パーティション分割テーブルと時間別パーティション分割テーブルの両方でサポートされています。

必要な権限

既存のパーティションを上書きする場合や、既存のパーティションにデータを追加する場合は、少なくとも次の権限が付与されている必要があります。

  • bigquery.tables.create
  • bigquery.tables.updateData
  • bigquery.jobs.create

追加するデータまたは上書きに使用するデータにアクセスするには、bigquery.tables.getData などの権限が追加で必要になる場合もあります。

次の事前定義済みの IAM ロールには bigquery.tables.updateData 権限と bigquery.tables.create 権限が含まれています。

  • bigquery.dataEditor
  • bigquery.dataOwner
  • bigquery.admin

次の事前定義済みの IAM ロールには bigquery.jobs.create 権限が含まれています。

  • bigquery.user
  • bigquery.jobUser
  • bigquery.admin

また、bigquery.datasets.create 権限を持つユーザーがデータセットを作成すると、そのデータセットに対する bigquery.dataOwner アクセス権がユーザーに付与されます。bigquery.dataOwner アクセス権により、ユーザーはデータセット内のテーブルとパーティションに対してデータの追加と上書きを行う権限が付与されます。

BigQuery での IAM のロールと権限について詳しくは、事前定義されたロールと権限をご覧ください。

読み込みジョブの使用

パーティションに対するデータの追加や上書きを行うには、bq load コマンドを使用するか、jobs.insert メソッドを呼び出して load ジョブを構成します。Cloud Console では、読み込みジョブでのパーティションへのデータの追加とパーティションの上書きはサポートされていません。

読み込みジョブを使用して特定のパーティションでデータを追加または上書きする場合は、次の点に注意してください。

  • Cloud Storage からデータを読み込む場合は、バケットが BigQuery データセットと同じロケーションにある必要があります。
  • 読み込むデータが、テーブルのパーティショニング スキームに準拠している必要があります。パーティションに書き込まれるすべての行は、パーティションの日付内に収まる値を持つ必要があります。
  • 1 つのパーティション分割テーブル内のパーティションはテーブルのスキーマを共有するので、パーティションのデータを置き換えてもテーブルのスキーマは置き換えられません。その代わりに、新しいデータのスキーマがテーブルのスキーマに適合している必要があります。読み込みジョブでテーブルのスキーマを更新する方法については、テーブル スキーマの管理をご覧ください。
  • 取り込み時間分割テーブルにデータを追加するときにパーティション デコレータを指定しないと、現在のパーティションが使用されます。

読み込みジョブを使用して、パーティション分割テーブルデータを追加または上書きするには、宛先テーブルとパーティション デコレータを指定し、書き込み処理フラグを次のいずれかに設定します。

コマンドライン オプション API オプション 説明
--noreplace WRITE_APPEND 既存のパーティションにデータを追加します。書き込み処理オプションが指定されていない場合は、デフォルトのアクションとしてパーティションにデータが追加されます。
--replace WRITE_TRUNCATE パーティションを上書き(書き換え)します。

パーティション デコレータは特定の日付を表しており、次の形式になります。

$YYYYMMDD

たとえば、次のコマンドは、mydataset.table1 という名前のパーティション分割テーブルの 2016 年 1 月 1 日(20160101)のパーティション全体のデータを置き換えます。JSON データは Cloud Storage バケットから読み込まれます。

bq load \
--replace \
--source_format=NEWLINE_DELIMITED_JSON \
'mydataset.table1$20160101' \
gs://mybucket/myfile.json

クエリジョブの使用

パーティションに対するデータの追加や上書きを行うには、bq query コマンドを使用するか、jobs.insert メソッドを呼び出して query ジョブを構成します。Cloud Console では、クエリジョブでのパーティションへのデータの追加とパーティションの上書きはサポートされていません。

クエリジョブを使用してパーティションにデータを追加する場合やパーティションを上書きする場合は、次の点に注意してください。

  • クエリするテーブルは、データを追加または上書きするテーブルと同じロケーションにある必要があります。
  • 取り込み時間分割テーブルのパーティションにデータを追加したりパーティションを上書きしたりする場合は、レガシー SQL 構文または標準 SQL 構文を使用できます。
  • 分割テーブルのパーティションにデータを追加したりパーティションを上書きしたりする場合は、クエリで標準 SQL 構文を使用する必要があります。現時点では、分割テーブルをクエリする場合や、クエリ結果を分割テーブルに書き込む場合には、レガシー SQL がサポートされていません。
  • クエリ結果をパーティションに書き込む場合、パーティションに書き込まれるデータは、テーブルのパーティショニング スキームに準拠している必要があります。パーティションに書き込まれるすべての行は、パーティションの日付内に収まる値を持つ必要があります。
  • 取り込み時間分割テーブルにデータを追加するときにパーティション デコレータを指定しないと、現在のパーティションが使用されます。

クエリ結果を使用してパーティションにデータを追加する、またはパーティションを上書きするには、宛先テーブルとパーティション デコレータを指定し、書き込み処理を次のいずれかに設定します。

コマンドライン オプション API オプション 説明
--append_table WRITE_APPEND 既存のパーティションにクエリ結果を追加します。
--replace WRITE_TRUNCATE クエリ結果を使用してパーティションを上書き(書き換え)します。

たとえば次のコマンドでは、クエリ結果を使用して、table1 の 2016 年 3 月 1 日(20160301)のパーティションのデータが修正されます。

bq query \
--use_legacy_sql=false \
--replace \
--destination_table 'mydataset.table1$20160301' \
'SELECT
  column1,
  column2
FROM
  mydataset.mytable'

宛先テーブルが存在し、かつ分割されていない場合は、次のエラーが返されます。BigQuery error in query operation: Error processing job 'project_id job_id' Incompatible table partitioning specification. Expects partitioning specification interval (type:day), but input partitioning specification is none`.

クエリ結果を使用してデータを追加または上書きする方法の詳細については、クエリ結果の書き込みをご覧ください。

DML ステートメントを使用したパーティション分割テーブルデータの変更

標準 SQL 言語の DML ステートメントを使用して、パーティション分割テーブルのデータを変更できます。DML ステートメントを使用すると、行の一括更新、挿入、および削除を実行できます。パーティション分割テーブルでの DML の使用例については、DML ステートメントを使用したパーティション分割テーブルデータの更新をご覧ください。

レガシー SQL は DML ステートメントをサポートしていません。レガシー SQL を使用してデータを更新または削除するには、パーティション分割テーブルを削除してから、新しいデータでテーブルを再作成する必要があります。または、データを変更し、クエリ結果を新しいパーティション分割テーブルに書き込むクエリを記述することもできます。

分割テーブルデータのコピー

パーティション分割テーブルを次の方法でコピーできます。

  • Cloud Console を使用する
  • bq コマンドライン ツールの bq cp コマンドを使用する
  • jobs.insert API メソッドを呼び出して copy ジョブを構成する
  • クライアント ライブラリを使用する

テーブルのコピーの詳細については、テーブルのコピーをご覧ください。

1 つ以上のパーティションをコピーするには、bq コマンドライン ツールの bq cp コマンドを使用するか、jobs.insert API メソッドを呼び出して copy ジョブを構成します。現在のところ、Cloud Console ではパーティションのコピーはサポートされていません。

パーティションのコピーの詳細については、パーティションのコピーをご覧ください。

パーティション分割テーブルへのデータのストリーミング

特定のパーティションにデータをストリーミングするには、ストリーミング先のテーブルの tableId を指定するときにパーティション デコレータを使用します。たとえば、次のコマンドを実行すると、2017 年 1 月 1 日($20170101)のパーティション全体のデータを、mydataset.mytable という名前のパーティション分割テーブルに 1 行がストリーミングされます。

echo '{"a":1, "b":2}' | bq insert 'mydataset.mytable$20170101'

このコマンドは、パーティション デコレータの使用を示すために使用されています。bq insert コマンドは、テスト専用です。データを BigQuery にストリーミングするには、API の tabledata.insertAll メソッドを使用します。データをパーティションにストリーミングする方法の詳細については、パーティション分割テーブルへのストリーミングをご覧ください。

パーティション デコレータを使用してストリーミングを行う際は、現在の UTC 時刻に基づき、過去 30 日以内のパーティションと現在の日付から 5 日後までのパーティションにストリーミングできます。この範囲に含まれない日付のパーティションに書き込むには、読み込みジョブまたはクエリジョブを使用します。時間別パーティション分割テーブルの場合、パーティションデコレータを使用したストリーミングはサポートされていないため、ベーステーブルにストリーミングする必要があります。

データをストリーミングするときに、時間パーティション分割テーブルを宛先テーブルとして指定すると、各パーティションでストリーミング バッファが保持されます。writeDisposition プロパティを WRITE_TRUNCATE に設定すると、パーティションを上書きする読み込み、クエリ、またはコピーのジョブを実行したときにストリーミング バッファが保持されます。ストリーミング バッファを削除するには、そのパーティションに対して tables.get を呼び出し、ストリーミング バッファが空であることを確認します。ストリーミング バッファの詳細については、パーティショニング オプションの比較をご覧ください。

テーブルデータのエクスポート

パーティション分割テーブルからすべてのデータをエクスポートする処理は、分割されていないテーブルからデータをエクスポートする処理と同じプロセスです。詳細については、テーブルデータのエクスポートをご覧ください。個々のパーティションからデータをエクスポートするには、テーブル名にパーティション デコレータ $date を追加します。例: mytable$20160201

テーブル名にパーティション名を追加して、__NULL____UNPARTITIONED__ のパーティションからデータをエクスポートすることもできます。たとえば、mytable$__NULL__mytable$__UNPARTITIONED__ です。

パーティション分割テーブルデータは、CSV、JSON、Avro 形式でエクスポートできます。現時点では、データを Cloud Storage バケットにエクスポートする必要があります。ローカルマシンへのエクスポートはサポートされていません。ただし、Cloud Console を使用してクエリ結果をダウンロードして保存できます。

次のステップ

パーティション分割テーブルの操作の詳細については、次をご覧ください。