테이블 데이터 페이지 나누기

이 문서에서는 BigQuery REST API를 사용하여 테이블 데이터 및 쿼리 결과 페이지를 나누는 방법을 설명합니다.

API를 사용하여 결과 페이지 나누기

모든 *collection*.list 메서드는 특정한 상황에서 페이지로 나눈 결과를 반환합니다. 페이지당 결과 수는 maxResults 속성에 의해 제어됩니다.

메서드 페이지 나누기 기준 기본값 maxResults 최댓값 maxResults 최댓값 maxFieldValues
Tabledata.list 응답 크기가 10MB1를 초과하는 데이터 또는 maxResults 행보다 많은 경우 페이지로 나눈 결과를 반환합니다. 100,000 무제한 무제한
기타 모든 *collection*.list 메서드 응답이 maxResults 행을 초과하는 동시에 최대 한도 미만인 경우 페이지로 나눈 결과를 반환합니다. 10,000 무제한 300,000

결과가 바이트 또는 필드 한도보다 크면 한도에 맞도록 결과가 잘립니다. 한 행이 바이트 또는 필드 한도보다 크면 tabledata.list는 쿼리 결과에 대한 최대 행 크기 한도와 일치하는 최대 100MB 데이터1로 반환할 수 있습니다.

1행 크기는 행 데이터의 내부 표현을 기준으로 하므로 근사치입니다. 최대 행 크기 한도는 쿼리 작업 실행의 특정 단계에서 적용됩니다.

jobs.getQueryResult는 지원을 통해 명시적으로 요청하지 않는 한 20MB의 데이터를 반환할 수 있습니다.

페이지는 전체 행 수의 하위 집합입니다. 결과 데이터가 한 페이지를 넘는 경우 결과 데이터에 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"]}");
        }
    }
}

자바

이 샘플을 사용해 보기 전에 BigQuery 빠른 시작: 클라이언트 라이브러리 사용의 자바 설정 안내를 따르세요. 자세한 내용은 BigQuery 자바 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용 Google 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용 Google Cloud 클라이언트 라이브러리는 기본적으로 자동 페이지 나누기를 수행하므로 사용자가 직접 페이지 나누기를 구현할 필요가 없습니다. 예를 들면 다음과 같습니다.

// Import the Google Cloud client library using default credentials
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery();

async function browseTable() {
  // Retrieve a table's rows using manual pagination.

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const datasetId = 'my_dataset'; // Existing dataset
  // const tableId = 'my_table'; // Table to create

  const 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`;

  // Create table reference.
  const dataset = bigquery.dataset(datasetId);
  const destinationTable = dataset.table(tableId);

  // For all options, see https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#jobconfigurationquery
  const queryOptions = {
    query: query,
    destination: destinationTable,
  };

  // Run the query as a job
  const [job] = await bigquery.createQueryJob(queryOptions);

  // For all options, see https://cloud.google.com/bigquery/docs/reference/v2/jobs/getQueryResults
  const queryResultsOptions = {
    // Retrieve zero resulting rows.
    maxResults: 0,
  };

  // Wait for the job to finish.
  await job.getQueryResults(queryResultsOptions);

  function manualPaginationCallback(err, rows, nextQuery) {
    rows.forEach(row => {
      console.log(`name: ${row.name}, ${row.total_people} total people`);
    });

    if (nextQuery) {
      // More results exist.
      destinationTable.getRows(nextQuery, manualPaginationCallback);
    }
  }

  // For all options, see https://cloud.google.com/bigquery/docs/reference/v2/tabledata/list
  const getRowsOptions = {
    autoPaginate: false,
    maxResults: 20,
  };

  // Retrieve all rows.
  destinationTable.getRows(getRowsOptions, manualPaginationCallback);
}
browseTable();

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용 Google 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

임의 페이지 요청 및 list 중복 호출 방지

페이지를 뒤로 이동하거나 캐시된 pageToken 값을 사용하여 임의의 페이지로 건너뛸 경우, 페이지를 마지막으로 본 이후 데이터가 변경되었다는 명확한 징후는 없지만 페이지의 데이터가 변경되었을 수 있습니다. Etag 속성을 사용하여 이 문제를 완화할 수 있습니다.

모든 collection.list 메서드(Tabledata 제외)는 결과에 Etag 속성을 반환합니다. 이 속성은 마지막 요청 이후 페이지가 변경되었는지 여부를 확인하는 데 사용할 수 있는 페이지 결과의 해시입니다. Etag 값을 사용하여 BigQuery에 요청하면 BigQuery는 Etag 값을 API가 반환한 ETag 값과 비교하고 ETag 값의 일치 여부에 따라 응답합니다. ETag를 사용하면 다음과 같은 방법으로 list 중복 호출을 방지할 수 있습니다.

  • 값이 변경된 경우에만 list 값을 반환하려는 경우:

    값이 변경된 경우에만 한 페이지 분량의 list 값을 반환하려는 경우, HTTP 'if-none-match' 헤더를 사용하여 이전에 저장된 ETag로 list를 호출할 수 있습니다. 제공한 ETag가 서버의 ETag와 일치하지 않으면 BigQuery는 한 페이지 분량의 새로운 list 값을 반환합니다. ETag가 일치하면 BigQuery는 HTTP 304 'Not Modified(수정되지 않음)' 결과를 값 없이 반환합니다. 사용자가 BigQuery에 저장된 정보를 주기적으로 채울 수 있는 웹페이지가 이러한 예시에 해당합니다. 데이터가 변경되지 않은 경우, ETag와 if-none-match 헤더를 사용하면 BigQuery에 대한 list 중복 호출을 방지할 수 있습니다.

  • 값이 변경되지 않은 경우에만 list 값을 반환하려는 경우:

    list 값이 변경되지 않은 경우에만 한 페이지 분량의 list 값을 반환하려는 경우, HTTP 'if-match' 헤더를 사용할 수 있습니다. BigQuery는 ETag 값을 비교하여 결과가 변경되지 않은 경우에 결과 페이지를 반환하고, 페이지가 변경된 경우에는 412 '전제 조건 미충족' 결과를 반환합니다.

참고: ETag는 list 중복 호출을 피할 수 있는 훌륭한 방법이며, 동일한 메서드를 적용하여 객체의 변경 여부도 확인할 수 있습니다. 예를 들어 특정 테이블에 대해 Get 요청을 수행하고 ETag를 사용하여 전체 응답을 반환하기 전에 테이블이 변경되었는지 확인할 수 있습니다.

쿼리 결과 페이징

각 쿼리는 대상 테이블에 씁니다. 대상 테이블이 제공되지 않으면 BigQuery API는 임시 익명 테이블에 대한 참조로 대상 테이블 속성을 자동으로 채웁니다.

API

jobs.config.query.destinationTable 필드를 읽어 쿼리 결과가 쓰인 테이블을 확인합니다. 쿼리 결과를 읽으려면 tabledata.list를 호출합니다.

자바

이 샘플을 사용해 보기 전에 BigQuery 빠른 시작: 클라이언트 라이브러리 사용의 자바 설정 안내를 따르세요. 자세한 내용은 BigQuery 자바 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());
    }
  }
}

Node.js

이 샘플을 사용해 보기 전에 BigQuery 빠른 시작: 클라이언트 라이브러리 사용의 Node.js 설정 안내를 따르세요. 자세한 내용은 BigQuery Node.js API 참조 문서를 확인하세요.

// Import the Google Cloud client library using default credentials
const {BigQuery} = require('@google-cloud/bigquery');
const bigquery = new BigQuery();

async function queryPagination() {
  // Run a query and get rows using automatic pagination.

  const 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`;

  // Run the query as a job.
  const [job] = await bigquery.createQueryJob(query);

  // Wait for job to complete and get rows.
  const [rows] = await job.getQueryResults();

  console.log('Query results:');
  rows.forEach(row => {
    console.log(`name: ${row.name}, ${row.total_people} total people`);
  });
}
queryPagination();

Python

QueryJob.result 메서드는 쿼리 결과의 iterable을 반환합니다. 다른 방법은 다음과 같습니다.

  1. QueryJob.destination 속성을 읽습니다. 구성되지 않은 경우 이 속성은 API에 의해 임시 익명 테이블에 대한 참조로 설정됩니다.
  2. Client.get_table 메서드를 사용하여 테이블 스키마를 가져옵니다.
  3. Client.list_rows 메서드를 사용하여 대상 테이블의 모든 행에 대해 iterable을 만듭니다.

이 샘플을 사용해 보기 전에 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"]))