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

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

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

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

메서드 페이지 나누기 기준 `maxResults` 기본값 `maxResults` 최댓값
`Tabledata.list` 응답 크기가 10MB의 직렬화된 JSON보다 크거나 `maxResults` 행보다 많은 경우, 페이지로 나눈 결과를 반환합니다. 100,000 100,000
다른 모든 `*collection*.list` 메서드 응답이 `maxResults` 행보다 많은 경우 페이지로 나눈 결과를 반환합니다. 50 1,000

maxResults를 위에 나열된 최댓값보다 큰 값으로 설정하면 최댓값을 기준으로 결과가 페이지로 나뉩니다.

페이지는 전체 행 수의 하위 집합입니다. 결과 데이터가 한 페이지를 넘는 경우 결과 데이터에 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 Java API 참조 문서를 확인하세요.

TableId tableIdObject = TableId.of(datasetName, tableName);
// This example reads the result 100 rows per RPC call. If there's no need to limit the number,
// simply omit the option.
TableResult tableData =
    bigquery.listTableData(tableIdObject, TableDataListOption.pageSize(100));
for (FieldValueList row : tableData.iterateAll()) {
  // do something with the row
}

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)
	}

	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 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용 Google 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 클라이언트 라이브러리는 기본적으로 자동 페이지 나누기를 수행하므로 사용자가 직접 페이지 나누기를 구현할 필요가 없습니다. 예를 들면 다음과 같습니다.

# TODO(developer): Import the client library.
# from google.cloud import bigquery

# TODO(developer): 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용 Google 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를 호출합니다.

Python

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

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

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

# TODO(developer): Import the client library.
# from google.cloud import bigquery

# TODO(developer): 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"]))