Usa la paginación con la API de BigQuery

En este documento, se describe cómo leer datos de tablas y resultados de consultas en conjuntos de datos grandes con la paginación de la API de BigQuery.

Con la paginación, BigQuery divide un conjunto de datos grande en fragmentos más pequeños llamados páginas. Para la mayoría de los usuarios, las bibliotecas cliente de Cloud controlan este proceso automáticamente, pero también puedes controlar la paginación de forma manual para casos de uso específicos, como las aplicaciones web.

Usa la paginación automática

Las bibliotecas cliente de Cloud controlan los detalles de bajo nivel de la paginación de la API y proporcionan una experiencia similar a un iterador. Cuando iteras los resultados, la biblioteca recupera automáticamente la siguiente página de datos cuando es necesario.

En los siguientes ejemplos, se muestra cómo iterar automáticamente los datos de tablas de BigQuery.

C#

Antes de probar este ejemplo, sigue las instrucciones de configuración para C# incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para C#.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.


using Google.Api.Gax;
using Google.Apis.Bigquery.v2.Data;
using Google.Cloud.BigQuery.V2;
using System;
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"]}");
        }
    }
}

Go

Antes de probar este ejemplo, sigue las instrucciones de configuración para Go incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Go.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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
}

Java

Antes de probar este ejemplo, sigue las instrucciones de configuración para Java incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Java.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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

Node.js

Antes de probar este ejemplo, sigue las instrucciones de configuración para Node.js incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Node.js.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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

Antes de probar este ejemplo, sigue las instrucciones de configuración para PHP incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para PHP.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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 probar este ejemplo, sigue las instrucciones de configuración para Python incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Python.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.


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 probar este ejemplo, sigue las instrucciones de configuración para Ruby incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Ruby.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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

Controla el tamaño de la página

Puedes especificar la cantidad máxima de filas que se muestran en cada solicitud de red configurando un tamaño de página. Establecer el tamaño de la página es útil para optimizar el uso de la red o ajustar los datos en la memoria.

En la mayoría de las bibliotecas cliente, puedes usar un parámetro max_results o page_size cuando llamas a métodos como list_rows o query.

Usa la paginación manual con tokens de página

La paginación manual es útil para las aplicaciones sin estado, como un servicio web en el que un usuario hace clic en Siguiente para ver el siguiente conjunto de resultados. En este caso, el servidor no mantiene un iterador activo entre las solicitudes.

En su lugar, usa un token de página de la siguiente manera:

  1. Solicita una página. Llama a la API y recibe un parámetro pageToken junto con las filas.
  2. Reanudar En la siguiente solicitud, vuelve a pasar ese mismo parámetro pageToken a BigQuery para recuperar el siguiente fragmento de datos.

En los siguientes ejemplos, se muestra cómo recuperar un token de página y usarlo para recuperar la siguiente página de resultados de la búsqueda.

API

Lee el campo jobs.config.query.destinationTable para determinar la tabla en la que se escribieron los resultados de la consulta. Llama a tabledata.list para leer los resultados de la consulta.

Java

Antes de probar este ejemplo, sigue las instrucciones de configuración para Java incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Java.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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 main(String[] args) {
    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));

      // First Page
      results
          .getValues()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,\n", val.toString())));

      while (results.hasNextPage()) {
        // Remaining Pages
        results = results.getNextPage();
        results
            .getValues()
            .forEach(row -> row.forEach(val -> System.out.printf("%s,\n", val.toString())));
      }

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

Para establecer la cantidad de filas que se muestran en cada página, usa un trabajo GetQueryResults y establece la opción pageSize del objeto QueryResultsOption que pasas, como se muestra en el siguiente ejemplo:

TableResult result = job.getQueryResults();
QueryResultsOption queryResultsOption = QueryResultsOption.pageSize(20);

TableResult result = job.getQueryResults(queryResultsOption);

Node.js

Antes de probar este ejemplo, sigue las instrucciones de configuración para Node.js incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Node.js.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.

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

El método QueryJob.result muestra un iterable de los resultados de la consulta. O, como alternativa:

  1. Lee la propiedad QueryJob.destination. Si la propiedad no está configurada, la API la establece en una referencia a una tabla anónima temporal.
  2. Obtén el esquema de la tabla con el método Client.get_table.
  3. Crea un iterable en todas las filas de la tabla de destino con el método Client.list_rows.

Antes de probar este ejemplo, sigue las instrucciones de configuración para Python incluidas en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Para obtener más información, consulta la documentación de referencia de la API de BigQuery para Python.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

Antes de ejecutar muestras de código, configura la variable de entorno GOOGLE_CLOUD_UNIVERSE_DOMAIN como s3nsapis.fr.


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

Optimiza con ETags

Cuando retrocedes la página o saltas a páginas arbitrarias con valores de pageToken almacenados en caché, es posible que los datos de tus páginas hayan cambiado desde la última vez que se vieron. Para mitigar este resultado, puedes usar la propiedad etag.

Cada método collection.list (excepto Tabledata) muestra una propiedad etag en el resultado. Esta propiedad genera un hash de los resultados de la página que se pueden usar para verificar si esta cambió desde la última solicitud. Cuando realizas una solicitud a BigQuery con un valor Etag, BigQuery compara el valor ETag con el valor de ETag que la API mostró y responde si esos valores coinciden. Puedes usar las ETag para evitar llamadas redundantes a las listas de la siguiente manera:

  • Para devolver valores solo si cambiaron, haz una llamada a la lista con un ETag almacenado con anterioridad usando el encabezado HTTP If-None-Match. Si los ETags coinciden, BigQuery devuelve un código de estado HTTP 304 Not Modified y no devuelve datos, lo que ahorra ancho de banda.
  • Para devolver valores solo si no cambiaron, usa el encabezado HTTP If-Match. BigQuery devuelve un 412 Precondition Failed si la página cambió.
Nota: A pesar de que los ETag son una excelente manera de evitar la realización de llamadas redundantes a las listas, puedes aplicar los mismos métodos para identificar si algún objeto cambió. Por ejemplo, puedes realizar una solicitud `GET` para una tabla específica y usar ETag para determinar si la tabla cambió antes de mostrar la respuesta completa.

Referencia: Límites y criterios de la API

Todos los métodos *collection*.list muestran resultados paginados en determinadas circunstancias. La propiedad maxResults limita la cantidad de resultados por página.

Método Criterios de paginación Límite predeterminado de maxResults Límite máximo de maxResults Límite máximo de maxFieldValues
tabledata.list Muestra resultados paginados si el tamaño de la respuesta supera los 10 MB1 de datos o más de las filas de maxResults. Ilimitado Ilimitado Ilimitado
Todos los demás métodos *collection*.list Muestra resultados paginados si el tamaño de la respuesta supera las filas en maxResults y también es inferior a los límites máximos. 10,000 Ilimitado 300,000

Si el resultado es mayor que el límite de bytes o campos, el resultado se corta para ajustarlo al límite. Si una fila supera el límite de bytes o campos, el método tabledata.list puede devolver hasta 100 MB de datos1, lo que coincide con el límite máximo de tamaño de fila para los resultados de la consulta. No hay un tamaño mínimo por página, y algunas páginas pueden mostrar más filas que otras.

El método de la API de REST jobs.getQueryResults puede devolver 20 MB de datos, a menos que solicites explícitamente una cantidad mayor a través del equipo de asistencia.

1 El tamaño de la fila es aproximado, ya que se basa en la representación interna de los datos de la fila. Este se aplica durante ciertas etapas de la ejecución del trabajo de consulta.