Como fazer paginação por dados da tabela

Este documento descreve como percorrer os dados da tabela e os resultados da consulta usando a API REST do BigQuery.

Como fazer paginação de resultados usando a API

Em todos os métodos *collection*.list são retornadas páginas de resultados sob certas circunstâncias. O número de resultados por página é controlado pela propriedade maxResults.

Método Critérios de paginação Valor padrão de maxResults Valor máximo de maxResults
Tabledata.list Retorna resultados paginados se o tamanho da resposta for maior que 10 MB de JSON serializado ou mais do que maxResults linhas. 100.000 100.000
Todos os outros métodos *collection*.list Retorna resultados paginados se a resposta tiver mais do que maxResults linhas. 50 1.000

Se você define maxResults como um valor maior do que o máximo listado acima, os resultados são exibidos em páginas com base no valor máximo.

Cada página é um subconjunto do número total de linhas. Quando há mais de uma página de resultados, é incluída a propriedade pageToken nos dados. Para recuperar a próxima página de resultados, faça outra chamada de list e inclua o valor do token como um parâmetro de URL chamado pageToken.

O método tabledata.list, usado para fazer a paginação dos dados da tabela, usa um valor de ajuste de linha ou token de página. Para mais informações, consulte Como navegar pelos dados da tabela.

Os exemplos a seguir demonstram paginação por meio de dados da Tabela do BigQuery.

C#

Antes de testar essa amostra, siga as instruções de configuração para C# no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em C# (em inglês).


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

Antes de testar essa amostra, siga as instruções de configuração para Java no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Java (em inglês).

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

Antes de testar essa amostra, siga as instruções de configuração para Go no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Go (em inglês).

Nas bibliotecas de cliente do Google Cloud para Go, a paginação dos resultados é feita automaticamente por padrão. Portanto, não é necessário implementá-la. Por exemplo:

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

Antes de testar essa amostra, siga as instruções de configuração para Node.js no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Node.js (em inglês).

Nas bibliotecas de cliente do Google Cloud para Node.js, a paginação dos resultados é feita automaticamente por padrão. Portanto, não é necessário implementá-la. Por exemplo:


// 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

Antes de testar esta amostra, siga as instruções de configuração para PHP no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em PHP (em inglês).

A paginação acontece automaticamente nas bibliotecas de cliente do Cloud para PHP usando a função do gerador rows, que busca a próxima página de resultados durante a iteração.

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

Antes de testar essa amostra, siga as instruções de configuração para Python no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Python (em inglês).

Nas bibliotecas de cliente do Google Cloud para Python, a paginação dos resultados é feita automaticamente por padrão. Portanto, não é necessário implementá-la. Por exemplo:


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

Antes de testar esta amostra, siga as instruções de configuração para Ruby no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Ruby (em inglês).

A paginação acontece automaticamente nas bibliotecas de cliente do Cloud para Ruby usando Table#data e Data#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

Como solicitar páginas arbitrárias e evitar chamadas de lista redundantes

Quando você volta ou avança para uma página arbitrária usando os valores de pageToken em cache, os dados exibidos nas suas páginas talvez não sejam os mesmos visualizados no último acesso, mas não há uma indicação clara disso. Para minimizar esse problema, use a propriedade Etag.

Todo método collection.list (exceto para Tabledata) retorna uma propriedade Etag no resultado. Essa propriedade é um hash dos resultados da página que pode ser usado para verificar se a página foi alterada desde a última solicitação. Quando você fizer uma solicitação ao BigQuery com um valor de Etag, o BigQuery compara o valor de Etag com o valor de ETag retornado pela API e responde com base na correspondência dos valores de ETag. É possível usar ETags para ajudar a evitar chamadas redundantes de lista das seguintes maneiras:

  • Para retornar valores da lista, em caso de alteração:

    Para retornar uma página de valores de lista se os valores tiverem sido alterados, faça uma chamada de lista com uma ETag armazenada anteriormente usando o cabeçalho HTTP "if-none-match". Se a ETag fornecida não corresponder à ETag no servidor, será retornada uma página dos novos valores da lista no BigQuery. Se as ETags coincidirem, o BigQuery retornará uma mensagem HTTP 304 "Não modificado" e nenhum valor na lista. Um exemplo disso seria uma página da Web que os usuários periodicamente preenchem com informações armazenadas no BigQuery. É possível evitar que sejam feitas chamadas redundantes de lista ao BigQuery, se não existirem alterações nos dados usando o cabeçalho if-none-match com ETags.

  • Para retornar valores de listas apenas se os valores não tiverem sido mudados:

    Para retornar uma página de valores de lista se os valores não tiverem sido mudados, use o cabeçalho HTTP "if-match". O BigQuery fará a comparação dos valores de ETag e retornará a página de resultados se os valores não tiverem mudado ou retornará um resultado 412 "Pré-requisito falhou" se a página tiver mudado.

Observação: as ETags são uma boa maneira de evitar chamadas redundantes de lista, mas é possível aplicar esses mesmos métodos para identificar se houve alteração em quaisquer objetos. Por exemplo, é possível realizar uma solicitação Get de uma tabela específica e usar ETags para determinar se a tabela foi modificada antes de retornar a resposta completa.

Como paginar resultados da consulta

Cada consulta é gravada em uma tabela de destino. Se nenhuma tabela de destino for fornecida, a API do BigQuery preencherá automaticamente a propriedade da tabela de destino com uma referência a uma tabela anônima temporária.

API

Leia o campo jobs.config.query.destinationTable para determinar a tabela na qual os resultados da consulta foram gravados. Chame tabledata.list para ler os resultados da consulta.

Python

O método QueryJob.result retorna um iterável dos resultados da consulta. Como alternativa:

  1. Leia a propriedade QueryJob.destination. Se não for configurada, essa propriedade será definida pela API como uma referência a uma tabela anônima temporária.
  2. Receba o esquema da tabela com o método Client.get_table.
  3. Crie um iterável em todas as linhas na tabela de destino com o método Client.list_rows.

Antes de testar essa amostra, siga as instruções de configuração para Python no Guia de início rápido do BigQuery: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API BigQuery em Python (em inglês).


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"]))