テーブルデータのページ分割

このドキュメントでは、BigQuery REST API を使用してテーブルデータとクエリ結果のページ分割を行う方法について説明します。

API を使用した結果のページ分割

すべての *collection*.list メソッドから返される結果は、特定の状況においてページ分けされます。ページあたりの結果の数は、maxResults プロパティによって制御されます。

メソッド ページ分け基準 maxResults のデフォルト値 maxResults の最大値 maxFieldValues の最大値
Tabledata.list レスポンス サイズが 10 MB1 を超えるデータ、または maxResults 行を超える場合は、ページ分割された結果を返します。 100,000 無制限 無制限
その他すべての *collection*.list メソッド レスポンスが maxResults 行を超え、かつ上限を下回っている場合、ページ分けされた結果を返します。 10,000 無制限 300,000

結果がバイトまたはフィールドの上限を超えると、結果は上限に合わせてカットされます。1 行がバイトまたはフィールドの上限より大きい場合、tabledata.list は最大 100 MB のデータ 1 を返すことができます。これは、クエリ結果の最大行数制限に準拠しています。

1 行サイズは行データの内部表現に基づくため、概算値です。行の最大サイズに対する上限は、クエリジョブ実行の特定の段階で適用されます。

jobs.getQueryResult は、サポートを通じてより大きなデータサイズを明示的にリクエストした場合を除いて、20 MB のデータを返すことができます。

ページは全行数のサブセットです。結果が 1 ページ分のデータを超える場合、結果データには pageToken プロパティが追加されます。次のページの結果を取得するには、別の list 呼び出しを行い、トークン値を pageToken という名前の URL パラメータとして指定します。

テーブルデータのページ分割に使用する tabledata.list メソッドでは、行オフセット値またはページトークンを使用します。詳細については、テーブルデータの閲覧をご覧ください。

BigQuery テーブルデータをページ分割するサンプルを以下に示します。

C#

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


using Google.Api.Gax;
using Google.Apis.Bigquery.v2.Data;
using Google.Cloud.BigQuery.V2;
using System;
using System.Collections.Generic;
using System.Linq;

public class BigQueryBrowseTable
{
    public void BrowseTable(
        string projectId = "your-project-id"
    )
    {
        BigQueryClient client = BigQueryClient.Create(projectId);
        TableReference tableReference = new TableReference()
        {
            TableId = "shakespeare",
            DatasetId = "samples",
            ProjectId = "bigquery-public-data"
        };
        // Load all rows from a table
        PagedEnumerable<TableDataList, BigQueryRow> result = client.ListRows(
            tableReference: tableReference,
            schema: null
        );
        // Print the first 10 rows
        foreach (BigQueryRow row in result.Take(10))
        {
            Console.WriteLine($"{row["corpus"]}: {row["word_count"]}");
        }
    }
}

Java

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

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQuery.TableDataListOption;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TableResult;

// Sample to directly browse a table with optional paging
public class BrowseTable {

  public static void runBrowseTable() {
    // TODO(developer): Replace these variables before running the sample.
    String table = "MY_TABLE_NAME";
    String dataset = "MY_DATASET_NAME";
    browseTable(dataset, table);
  }

  public static void browseTable(String dataset, String table) {
    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();

      // Identify the table itself
      TableId tableId = TableId.of(dataset, table);

      // Page over 100 records. If you don't need pagination, remove the pageSize parameter.
      TableResult result = bigquery.listTableData(tableId, TableDataListOption.pageSize(100));

      // Print the records
      result
          .iterateAll()
          .forEach(
              row -> {
                row.forEach(fieldValue -> System.out.print(fieldValue.toString() + ", "));
                System.out.println();
              });

      System.out.println("Query ran successfully");
    } catch (BigQueryException e) {
      System.out.println("Query failed to run \n" + e.toString());
    }
  }
}

Go

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

Go 用の Cloud クライアント ライブラリでは、デフォルトで自動的にページ分けされるため、ページ分けを自分で実装する必要はありません。次に例を示します。

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
)

// browseTable demonstrates reading data from a BigQuery table directly without the use of a query.
// For large tables, we also recommend the BigQuery Storage API.
func browseTable(w io.Writer, projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	table := client.Dataset(datasetID).Table(tableID)
	it := table.Read(ctx)
	for {
		var row []bigquery.Value
		err := it.Next(&row)
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintln(w, row)
	}
	return nil
}

Node.js

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

Node.js 用の Cloud クライアント ライブラリでは、デフォルトで自動的にページ分けされるため、ページ分けを自分で実装する必要はありません。次に例を示します


// Import the Google Cloud client library and create a client
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery();

async function browseRows() {
  // Displays rows from "my_table" in "my_dataset".

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const datasetId = "my_dataset";
  // const tableId = "my_table";

  // List rows in the table
  const [rows] = await bigquery
    .dataset(datasetId)
    .table(tableId)
    .getRows();

  console.log('Rows:');
  rows.forEach(row => console.log(row));
}

PHP

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

PHP 用の Cloud クライアント ライブラリでジェネレータ関数 rows を使用すると、ページ分割が自動的に行われます。この関数はイテレーション中に結果の次のページをフェッチします。

use Google\Cloud\BigQuery\BigQueryClient;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $datasetId = 'The BigQuery dataset ID';
// $tableId   = 'The BigQuery table ID';
// $maxResults = 10;

$maxResults = 10;
$startIndex = 0;

$options = [
    'maxResults' => $maxResults,
    'startIndex' => $startIndex
];
$bigQuery = new BigQueryClient([
    'projectId' => $projectId,
]);
$dataset = $bigQuery->dataset($datasetId);
$table = $dataset->table($tableId);
$numRows = 0;
foreach ($table->rows($options) as $row) {
    print('---');
    foreach ($row as $column => $value) {
        printf('%s: %s' . PHP_EOL, $column, $value);
    }
    $numRows++;
}

Python

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

Python 用の Cloud クライアント ライブラリでは、デフォルトで自動的にページ分けされるため、ページ分けを自分で実装する必要はありません。次に例を示します。


from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the table to browse data rows.
# table_id = "your-project.your_dataset.your_table_name"

# Download all rows from a table.
rows_iter = client.list_rows(table_id)  # Make an API request.

# Iterate over rows to make the API requests to fetch row data.
rows = list(rows_iter)
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Download at most 10 rows.
rows_iter = client.list_rows(table_id, max_results=10)
rows = list(rows_iter)
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Specify selected fields to limit the results to certain columns.
table = client.get_table(table_id)  # Make an API request.
fields = table.schema[:2]  # First two columns.
rows_iter = client.list_rows(table_id, selected_fields=fields, max_results=10)
rows = list(rows_iter)
print("Selected {} columns from table {}.".format(len(rows_iter.schema), table_id))
print("Downloaded {} rows from table {}".format(len(rows), table_id))

# Print row data in tabular format.
rows = client.list_rows(table, max_results=10)
format_string = "{!s:<16} " * len(rows.schema)
field_names = [field.name for field in rows.schema]
print(format_string.format(*field_names))  # Prints column headers.
for row in rows:
    print(format_string.format(*row))  # Prints row data.

Ruby

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

Ruby 用 Cloud クライアント ライブラリTable#dataData#next を使用すると、ページ分割が自動的に行われます。

require "google/cloud/bigquery"

def browse_table
  bigquery = Google::Cloud::Bigquery.new project_id: "bigquery-public-data"
  dataset  = bigquery.dataset "samples"
  table    = dataset.table "shakespeare"

  # Load all rows from a table
  rows = table.data

  # Load the first 10 rows
  rows = table.data max: 10

  # Print row data
  rows.each { |row| puts row }
end

任意のページのリクエストと、冗長リスト呼び出しの回避

前のページに戻る場合、またはキャッシュされた pageToken の値を使用して任意のページにジャンプする場合、ページのデータが最後に表示された後で変更されている可能性がありますが、データが変更されたことは明確には示されません。これを確認するには、ETag プロパティを使用できます。

すべての collection.list メソッド(Tabledata 用を除く)は、結果で Etag プロパティを返します。このプロパティは、ページが最後のリクエスト以降に変更されているかどうかを確認するために使用できるページ結果のハッシュです。ETag 値を使用して BigQuery にリクエストを行うと、BigQuery はその ETag 値と API によって返された ETag 値を比較し、ETag 値が一致しているかどうかに基づいて応答します。次の方法で、冗長なリスト呼び出しを回避するために ETag を使用できます。

  • 値が変更されている場合にのみリスト値を返す場合:

    値が変更されている場合にのみリスト値のページを返す場合は、HTTP の If-None-Match ヘッダーを使用し、保存しておいた ETag を指定してリスト呼び出しを行うことができます。指定した ETag がサーバー上の ETag と一致しない場合、BigQuery は、新しいリスト値のページを返します。ETag が一致する場合、BigQuery は HTTP 304「Not Modified」という結果を返し、値を返しません。この例として、ユーザーが BigQuery に格納されている情報を定期的に入力するウェブページがあります。ETag と If-None-Match ヘッダーを使用することにより、データに変更がない場合に冗長なリスト呼び出しを避けることができます。

  • 値が変更されていない場合にのみリスト値を返す場合:

    リストの値が変更されていない場合にのみリスト値のページを返す場合は、HTTP の If-Match ヘッダーを使用できます。BigQuery は ETag 値を比較し、結果が変更されていない場合は結果のページを返します。ページが変更されている場合は、412「Precondition Failed」という結果を返します。

注: ETag は冗長なリスト呼び出しを避けるために有効な方法ですが、同じ方法を使用して、いずれかのオブジェクトが変更されたかどうかを確認できます。たとえば、特定のテーブルに対する get リクエストを実行し、完全なレスポンスが返される前に、ETag を使用して、テーブルが変更されているかどうかを判断できます。

クエリ結果のページ分割

各クエリは宛先テーブルに書き込みます。宛先テーブルが指定されていない場合、BigQuery API は宛先テーブル プロパティに一時匿名テーブルへの参照を自動的に挿入します。

API

jobs.config.query.destinationTable フィールドを読み取り、クエリ結果が書き込まれたテーブルを確認します。クエリ結果を読み取るには、tabledata.list を呼び出します。

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.QueryJobConfiguration;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TableResult;

// Sample to run query with pagination.
public class QueryPagination {

  public static void runQueryPagination() {
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String query =
        "SELECT name, SUM(number) as total_people"
            + " FROM `bigquery-public-data.usa_names.usa_1910_2013`"
            + " GROUP BY name"
            + " ORDER BY total_people DESC"
            + " LIMIT 100";
    queryPagination(datasetName, tableName, query);
  }

  public static void queryPagination(String datasetName, String tableName, String query) {
    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);
      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query)
              // save results into a table.
              .setDestinationTable(tableId)
              .build();

      bigquery.query(queryConfig);

      TableResult results =
          bigquery.listTableData(tableId, BigQuery.TableDataListOption.pageSize(20));

      results
          .getNextPage()
          .iterateAll()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString())));

      System.out.println("Query pagination performed successfully.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Query not performed \n" + e.toString());
    }
  }
}

Python

QueryJob.result メソッドは、クエリ結果のイテラブルを返します。または

  1. QueryJob.destination プロパティを読み取ります。構成されていない場合、API がこのプロパティに一時匿名テーブルへの参照を設定します。
  2. Client.get_table メソッドでテーブル スキーマを取得します。
  3. Client.list_rows メソッドを使用して、宛先テーブルのすべての行に対するイテラブルを作成します。

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


from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

query = """
    SELECT name, SUM(number) as total_people
    FROM `bigquery-public-data.usa_names.usa_1910_2013`
    GROUP BY name
    ORDER BY total_people DESC
"""
query_job = client.query(query)  # Make an API request.
query_job.result()  # Wait for the query to complete.

# Get the destination table for the query results.
#
# All queries write to a destination table. If a destination table is not
# specified, the BigQuery populates it with a reference to a temporary
# anonymous table after the query completes.
destination = query_job.destination

# Get the schema (and other properties) for the destination table.
#
# A schema is useful for converting from BigQuery types to Python types.
destination = client.get_table(destination)

# Download rows.
#
# The client library automatically handles pagination.
print("The query data:")
rows = client.list_rows(destination, max_results=20)
for row in rows:
    print("name={}, count={}".format(row["name"], row["total_people"]))