Use a API Legacy Streaming

Este documento descreve como transmitir dados para o BigQuery através do método tabledata.insertAll antigo.

Para novos projetos, recomendamos que use a API BigQuery Storage Write em vez do método tabledata.insertAll. A API Storage Write tem preços mais baixos e funcionalidades mais robustas, incluindo a semântica de entrega exatamente uma vez. Se estiver a migrar um projeto existente do método tabledata.insertAll para a API Storage Write, recomendamos que selecione a stream predefinida. O método tabledata.insertAll continua a ser totalmente suportado.

Antes de começar

  1. Certifique-se de que tem acesso de escrita ao conjunto de dados que contém a tabela de destino. A tabela tem de existir antes de começar a escrever dados na mesma, a menos que esteja a usar tabelas de modelos. Para mais informações sobre tabelas de modelos, consulte o artigo Crie tabelas automaticamente com tabelas de modelos.

  2. Consulte a política de quotas para dados de streaming.

  3. Verify that billing is enabled for your Google Cloud project.

  4. O streaming não está disponível através do nível gratuito. Se tentar usar o streaming sem ativar a faturação, recebe o seguinte erro: BigQuery: Streaming insert is not allowed in the free tier.

  5. Conceda funções de gestão de identidade e acesso (IAM) que dão aos utilizadores as autorizações necessárias para realizar cada tarefa neste documento.

Autorizações necessárias

Para transmitir dados para o BigQuery, precisa das seguintes autorizações do IAM:

  • bigquery.tables.updateData (permite-lhe inserir dados na tabela)
  • bigquery.tables.get (permite obter metadados de tabelas)
  • bigquery.datasets.get (permite obter metadados do conjunto de dados)
  • bigquery.tables.create (obrigatório se usar uma tabela de modelo para criar a tabela automaticamente)

Cada uma das seguintes funções predefinidas do IAM inclui as autorizações de que precisa para transmitir dados em stream para o BigQuery:

  • roles/bigquery.dataEditor
  • roles/bigquery.dataOwner
  • roles/bigquery.admin

Para mais informações acerca das funções e autorizações do IAM no BigQuery, consulte o artigo Funções e autorizações predefinidas.

Transmita dados para o BigQuery

C#

Antes de experimentar este exemplo, siga as C#instruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API C# BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.


using Google.Cloud.BigQuery.V2;

public class BigQueryTableInsertRows
{
    public void TableInsertRows(
        string projectId = "your-project-id",
        string datasetId = "your_dataset_id",
        string tableId = "your_table_id"
    )
    {
        BigQueryClient client = BigQueryClient.Create(projectId);
        BigQueryInsertRow[] rows = new BigQueryInsertRow[]
        {
            // The insert ID is optional, but can avoid duplicate data
            // when retrying inserts.
            new BigQueryInsertRow(insertId: "row1") {
                { "name", "Washington" },
                { "post_abbr", "WA" }
            },
            new BigQueryInsertRow(insertId: "row2") {
                { "name", "Colorado" },
                { "post_abbr", "CO" }
            }
        };
        client.InsertRows(datasetId, tableId, rows);
    }
}

Go

Antes de experimentar este exemplo, siga as Goinstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Go BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// Item represents a row item.
type Item struct {
	Name string
	Age  int
}

// Save implements the ValueSaver interface.
// This example disables best-effort de-duplication, which allows for higher throughput.
func (i *Item) Save() (map[string]bigquery.Value, string, error) {
	return map[string]bigquery.Value{
		"full_name": i.Name,
		"age":       i.Age,
	}, bigquery.NoDedupeID, nil
}

// insertRows demonstrates inserting data into a table using the streaming insert mechanism.
func insertRows(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: %w", err)
	}
	defer client.Close()

	inserter := client.Dataset(datasetID).Table(tableID).Inserter()
	items := []*Item{
		// Item implements the ValueSaver interface.
		{Name: "Phred Phlyntstone", Age: 32},
		{Name: "Wylma Phlyntstone", Age: 29},
	}
	if err := inserter.Put(ctx, items); err != nil {
		return err
	}
	return nil
}

Java

Antes de experimentar este exemplo, siga as Javainstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Java BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryError;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.InsertAllRequest;
import com.google.cloud.bigquery.InsertAllResponse;
import com.google.cloud.bigquery.TableId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// Sample to inserting rows into a table without running a load job.
public class TableInsertRows {

  public static void main(String[] args) {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    // Create a row to insert
    Map<String, Object> rowContent = new HashMap<>();
    rowContent.put("booleanField", true);
    rowContent.put("numericField", "3.14");
    // TODO(developer): Replace the row id with a unique value for each row.
    String rowId = "ROW_ID";
    tableInsertRows(datasetName, tableName, rowId, rowContent);
  }

  public static void tableInsertRows(
      String datasetName, String tableName, String rowId, Map<String, Object> rowContent) {
    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();

      // Get table
      TableId tableId = TableId.of(datasetName, tableName);

      // Inserts rowContent into datasetName:tableId.
      InsertAllResponse response =
          bigquery.insertAll(
              InsertAllRequest.newBuilder(tableId)
                  // More rows can be added in the same RPC by invoking .addRow() on the builder.
                  // You can omit the unique row ids to disable de-duplication.
                  .addRow(rowId, rowContent)
                  .build());

      if (response.hasErrors()) {
        // If any of the insertions failed, this lets you inspect the errors
        for (Map.Entry<Long, List<BigQueryError>> entry : response.getInsertErrors().entrySet()) {
          System.out.println("Response error: \n" + entry.getValue());
        }
      }
      System.out.println("Rows successfully inserted into table");
    } catch (BigQueryException e) {
      System.out.println("Insert operation not performed \n" + e.toString());
    }
  }
}

Node.js

Antes de experimentar este exemplo, siga as Node.jsinstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Node.js BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

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

async function insertRowsAsStream() {
  // Inserts the JSON objects into my_dataset:my_table.

  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
  // const datasetId = 'my_dataset';
  // const tableId = 'my_table';
  const rows = [
    {name: 'Tom', age: 30},
    {name: 'Jane', age: 32},
  ];

  // Insert data into a table
  await bigquery.dataset(datasetId).table(tableId).insert(rows);
  console.log(`Inserted ${rows.length} rows`);
}

PHP

Antes de experimentar este exemplo, siga as PHPinstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API PHP BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

use Google\Cloud\BigQuery\BigQueryClient;

/**
 * Stream data into bigquery
 *
 * @param string $projectId The project Id of your Google Cloud Project.
 * @param string $datasetId The BigQuery dataset ID.
 * @param string $tableId The BigQuery table ID.
 * @param string $data Json encoded data For eg,
 *    $data = json_encode([
 *       "field1" => "value1",
 *       "field2" => "value2",
 *    ]);
 */
function stream_row(
    string $projectId,
    string $datasetId,
    string $tableId,
    string $data
): void {
    // instantiate the bigquery table service
    $bigQuery = new BigQueryClient([
      'projectId' => $projectId,
    ]);
    $dataset = $bigQuery->dataset($datasetId);
    $table = $dataset->table($tableId);

    $data = json_decode($data, true);
    $insertResponse = $table->insertRows([
      ['data' => $data],
      // additional rows can go here
    ]);
    if ($insertResponse->isSuccessful()) {
        print('Data streamed into BigQuery successfully' . PHP_EOL);
    } else {
        foreach ($insertResponse->failedRows() as $row) {
            foreach ($row['errors'] as $error) {
                printf('%s: %s' . PHP_EOL, $error['reason'], $error['message']);
            }
        }
    }
}

Python

Antes de experimentar este exemplo, siga as Pythoninstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Python BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

from google.cloud import bigquery

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

# TODO(developer): Set table_id to the ID of table to append to.
# table_id = "your-project.your_dataset.your_table"

rows_to_insert = [
    {"full_name": "Phred Phlyntstone", "age": 32},
    {"full_name": "Wylma Phlyntstone", "age": 29},
]

errors = client.insert_rows_json(table_id, rows_to_insert)  # Make an API request.
if errors == []:
    print("New rows have been added.")
else:
    print("Encountered errors while inserting rows: {}".format(errors))

Ruby

Antes de experimentar este exemplo, siga as Rubyinstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Ruby BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

require "google/cloud/bigquery"

def table_insert_rows dataset_id = "your_dataset_id", table_id = "your_table_id"
  bigquery = Google::Cloud::Bigquery.new
  dataset  = bigquery.dataset dataset_id
  table    = dataset.table table_id

  row_data = [
    { name: "Alice", value: 5  },
    { name: "Bob",   value: 10 }
  ]
  response = table.insert row_data

  if response.success?
    puts "Inserted rows successfully"
  else
    puts "Failed to insert #{response.error_rows.count} rows"
  end
end

Não tem de preencher o campo insertID quando insere linhas. O exemplo seguinte mostra como evitar o envio de um insertID para cada linha quando faz streaming.

Java

Antes de experimentar este exemplo, siga as Javainstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Java BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryError;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.InsertAllRequest;
import com.google.cloud.bigquery.InsertAllResponse;
import com.google.cloud.bigquery.TableId;
import com.google.common.collect.ImmutableList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// Sample to insert rows without row ids in a table
public class TableInsertRowsWithoutRowIds {

  public static void main(String[] args) {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    tableInsertRowsWithoutRowIds(datasetName, tableName);
  }

  public static void tableInsertRowsWithoutRowIds(String datasetName, String tableName) {
    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.
      final BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();
      // Create rows to insert
      Map<String, Object> rowContent1 = new HashMap<>();
      rowContent1.put("stringField", "Phred Phlyntstone");
      rowContent1.put("numericField", 32);
      Map<String, Object> rowContent2 = new HashMap<>();
      rowContent2.put("stringField", "Wylma Phlyntstone");
      rowContent2.put("numericField", 29);
      InsertAllResponse response =
          bigquery.insertAll(
              InsertAllRequest.newBuilder(TableId.of(datasetName, tableName))
                  // No row ids disable de-duplication, and also disable the retries in the Java
                  // library.
                  .setRows(
                      ImmutableList.of(
                          InsertAllRequest.RowToInsert.of(rowContent1),
                          InsertAllRequest.RowToInsert.of(rowContent2)))
                  .build());

      if (response.hasErrors()) {
        // If any of the insertions failed, this lets you inspect the errors
        for (Map.Entry<Long, List<BigQueryError>> entry : response.getInsertErrors().entrySet()) {
          System.out.println("Response error: \n" + entry.getValue());
        }
      }
      System.out.println("Rows successfully inserted into table without row ids");
    } catch (BigQueryException e) {
      System.out.println("Insert operation not performed \n" + e.toString());
    }
  }
}

Python

Antes de experimentar este exemplo, siga as Pythoninstruções de configuração no início rápido do BigQuery com bibliotecas cliente. Para mais informações, consulte a API Python BigQuery documentação de referência.

Para se autenticar no BigQuery, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para bibliotecas de cliente.

from google.cloud import bigquery

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

# TODO(developer): Set table_id to the ID of table to append to.
# table_id = "your-project.your_dataset.your_table"

rows_to_insert = [
    {"full_name": "Phred Phlyntstone", "age": 32},
    {"full_name": "Wylma Phlyntstone", "age": 29},
]

errors = client.insert_rows_json(
    table_id, rows_to_insert, row_ids=[None] * len(rows_to_insert)
)  # Make an API request.
if errors == []:
    print("New rows have been added.")
else:
    print("Encountered errors while inserting rows: {}".format(errors))

Envie dados de data e hora

Para campos de data e hora, formate os dados no método tabledata.insertAll da seguinte forma:

Tipo Formato
DATE Uma string no formato "YYYY-MM-DD"
DATETIME Uma string no formato "YYYY-MM-DD [HH:MM:SS]"
TIME Uma string no formato "HH:MM:SS"
TIMESTAMP O número de segundos desde 01/01/1970 (a época Unix) ou uma string no formato "YYYY-MM-DD HH:MM[:SS]"

Envie dados de intervalo

Para campos com o tipo RANGE<T>, formate os dados no método tabledata.insertAll como um objeto JSON com dois campos, start e end. Os valores em falta ou NULL para os campos start e end representam limites ilimitados. Estes campos têm de ter o mesmo formato JSON suportado do tipo T, em que T pode ser um dos seguintes: DATE, DATETIME e TIMESTAMP.

No exemplo seguinte, o campo f_range_date representa uma coluna RANGE<DATE> numa tabela. É inserida uma linha nesta coluna através da API tabledata.insertAll.

{
    "f_range_date": {
        "start": "1970-01-02",
        "end": null
    }
}

Disponibilidade de dados da stream

Os dados estão disponíveis para análise em tempo real através de consultas GoogleSQL imediatamente após o BigQuery acusar a receção com êxito de um pedido tabledata.insertAll.

As linhas transmitidas recentemente para uma tabela particionada por tempo de ingestão têm temporariamente um valor NULL para a pseudocoluna _PARTITIONTIME. Para essas linhas, o BigQuery atribui o valor final não NULL da coluna PARTITIONTIME em segundo plano, normalmente, no prazo de alguns minutos. Em casos raros, esta ação pode demorar até 90 minutos.

Algumas linhas transmitidas recentemente podem não estar disponíveis para cópia de tabelas, normalmente durante alguns minutos. Em casos raros, esta ação pode demorar até 90 minutos. Para ver se os dados estão disponíveis para a cópia de tabelas, verifique a resposta tables.get para uma secção denominada streamingBuffer. Se a secção streamingBuffer estiver ausente, os seus dados estão disponíveis para cópia. Também pode usar o campo streamingBuffer.oldestEntryTime para identificar a idade dos registos no buffer de streaming.

Eliminação de duplicados dentro do possível

Quando fornece insertId para uma linha inserida, o BigQuery usa este ID para suportar a remoção de duplicados da melhor forma possível durante um máximo de um minuto. Ou seja, se transmitir a mesma linha com o mesmo insertId mais do que uma vez nesse período, o BigQuery pode remover as duplicadas das várias ocorrências dessa linha, retendo apenas uma dessas ocorrências.

O sistema espera que as linhas fornecidas com insertIds idênticos também sejam idênticas. Se duas linhas tiverem insertIds idênticos, não é possível determinar qual linha o BigQuery preserva.

A remoção de duplicados destina-se geralmente a cenários de repetição num sistema distribuído onde não existe forma de determinar o estado de uma inserção de streaming em determinadas condições de erro, como erros de rede entre o seu sistema e o BigQuery ou erros internos no BigQuery. Se repetir uma inserção, use o mesmo insertId para o mesmo conjunto de linhas, para que o BigQuery possa tentar remover duplicados dos seus dados. Para mais informações, consulte o artigo Resolva problemas de inserções de streaming.

A remoção de duplicados oferecida pelo BigQuery é baseada no melhor esforço e não deve ser usada como um mecanismo para garantir a ausência de duplicados nos seus dados. Além disso, o BigQuery pode degradar a qualidade da desduplicação de melhor esforço em qualquer altura para garantir uma maior fiabilidade e disponibilidade dos seus dados.

Se tiver requisitos de remoção de duplicados rigorosos para os seus dados, o Armazenamento de dados do Google Cloud é um serviço alternativo que suporta transações.

Desativar a remoção de duplicados com base no melhor esforço

Pode desativar a eliminação de duplicados da melhor forma não preenchendo o campo insertId para cada linha inserida. Esta é a forma recomendada de inserir dados.

Apache Beam e Dataflow

Para desativar a eliminação de duplicados da melhor forma quando usa o conetor BigQuery I/O do Apache Beam para Java, use o método ignoreInsertIds().

Remover duplicados manualmente

Para garantir que não existem linhas duplicadas após a conclusão do streaming, use o seguinte processo manual:

  1. Adicione insertId como uma coluna no esquema da tabela e inclua o valor insertId nos dados de cada linha.
  2. Depois de a transmissão em streaming parar, execute a seguinte consulta para verificar se existem duplicados:

    #standardSQL
    SELECT
      MAX(count) FROM(
      SELECT
        ID_COLUMN,
        count(*) as count
      FROM
        `TABLE_NAME`
      GROUP BY
        ID_COLUMN)

    Se o resultado for superior a 1, existem duplicados.
  3. Para remover duplicados, execute a seguinte consulta. Especifique uma tabela de destino, permita resultados grandes e desative o nivelamento de resultados.

    #standardSQL
    SELECT
      * EXCEPT(row_number)
    FROM (
      SELECT
        *,
        ROW_NUMBER()
              OVER (PARTITION BY ID_COLUMN) row_number
      FROM
        `TABLE_NAME`)
    WHERE
      row_number = 1

Notas acerca da consulta de remoção de duplicados:

  • A estratégia mais segura para a consulta de remoção de duplicados é segmentar uma nova tabela. Em alternativa, pode segmentar a tabela de origem com a disposição de escrita WRITE_TRUNCATE.
  • A consulta de remoção de duplicados adiciona uma coluna row_number com o valor 1 ao final do esquema da tabela. A consulta usa uma declaração SELECT * EXCEPT do GoogleSQL para excluir a coluna row_number da tabela de destino. O prefixo #standardSQL ativa o GoogleSQL para esta consulta. Em alternativa, pode selecionar nomes de colunas específicos para omitir esta coluna.
  • Para consultar dados em direto com duplicados removidos, também pode criar uma vista sobre a sua tabela através da consulta de remoção de duplicados. Tenha em atenção que os custos das consultas relativas à vista são calculados com base nas colunas selecionadas na sua vista, o que pode resultar em tamanhos de bytes analisados grandes.

Faça stream para tabelas particionadas por tempo

Quando transmite dados para uma tabela particionada por tempo, cada partição tem um buffer de streaming. O buffer de streaming é retido quando executa uma tarefa de carregamento, consulta ou cópia que substitui uma partição definindo a propriedade writeDisposition como WRITE_TRUNCATE. Se quiser remover o buffer de streaming, verifique se o buffer de streaming está vazio chamando tables.get na partição.

Particionamento por tempo de ingestão

Quando faz streaming para uma tabela particionada por tempo de ingestão, o BigQuery infere a partição de destino a partir da hora UTC atual.

Os dados recebidos recentemente são colocados temporariamente na partição __UNPARTITIONED__ enquanto estão no buffer de streaming. Quando existem dados não particionados suficientes, o BigQuery particiona os dados na partição correta. No entanto, não existe um SLA para o tempo que os dados demoram a sair da partição __UNPARTITIONED__. Uma consulta pode excluir dados no buffer de streaming de uma consulta filtrando os valores NULL da partição __UNPARTITIONED__ através de uma das pseudocolunas (_PARTITIONTIME ou _PARTITIONDATE, consoante o tipo de dados preferido).

Se estiver a transmitir dados para uma tabela particionada diariamente, pode substituir a inferência de data fornecendo um decorador de partição como parte do pedido.insertAll Inclua o decorator no parâmetro tableId. Por exemplo, pode fazer stream para a partição correspondente a 2021-03-01 para a tabela table1 usando o decorador de partição:

table1$20210301

Quando faz streaming com um decorador de partições, pode fazer streaming para partições nos últimos 31 dias e nos 16 dias seguintes em relação à data atual, com base na hora UTC atual. Para escrever em partições para datas fora destes limites permitidos, use um trabalho de carregamento ou de consulta, conforme descrito no artigo Anexar e substituir dados de tabelas particionadas.

O streaming com um decorador de partição só é suportado para tabelas particionadas diariamente. Não é suportado para tabelas particionadas por hora, mês ou ano.

Para testes, pode usar a ferramenta de linhas de comando bq comando CLI bq insert. Por exemplo, o seguinte comando transmite uma única linha para uma partição para a data 1 de janeiro de 2017 ($20170101) numa tabela particionada denominada mydataset.mytable:

echo '{"a":1, "b":2}' | bq insert 'mydataset.mytable$20170101'

Partição de colunas de unidades de tempo

Pode transmitir dados para uma tabela particionada numa coluna DATE, DATETIME ou TIMESTAMP que esteja entre 10 anos no passado e 1 ano no futuro. Os dados fora deste intervalo são rejeitados.

Quando os dados são transmitidos, são inicialmente colocados na partição __UNPARTITIONED__. Quando existem dados não particionados suficientes, o BigQuery reparticiona automaticamente os dados, colocando-os na partição adequada. No entanto, não existe um SLA para o tempo que os dados demoram a sair da partição __UNPARTITIONED__.

  • Nota: as partições diárias são processadas de forma diferente das partições por hora, mensais e anuais. Apenas os dados fora do intervalo de datas (últimos 7 dias a 3 dias futuros) são extraídos para a partição UNPARTITIONED, aguardando a repartição. Por outro lado, para uma tabela particionada por hora, os dados são sempre extraídos para a partição UNPARTITIONED e, posteriormente, reparticionados.

Crie tabelas automaticamente com tabelas de modelos

As tabelas de modelos oferecem um mecanismo para dividir uma tabela lógica em muitas tabelas mais pequenas para criar conjuntos de dados mais pequenos (por exemplo, por ID do utilizador). As tabelas de modelos têm várias limitações descritas abaixo. Em alternativa, as tabelas particionadas e as tabelas agrupadas são as formas recomendadas de alcançar este comportamento.

Para usar uma tabela de modelo através da API BigQuery, adicione um parâmetro templateSuffix ao seu pedido insertAll. Para a ferramenta de linhas de comando bq, adicione a flag template_suffix ao comando insert. Se o BigQuery detetar um parâmetro templateSuffix ou a flag template_suffix, trata a tabela segmentada como um modelo base. Cria uma nova tabela que partilha o mesmo esquema que a tabela segmentada e tem um nome que inclui o sufixo especificado:

<targeted_table_name> + <templateSuffix>

Ao usar uma tabela de modelo, evita a sobrecarga de criar cada tabela individualmente e especificar o esquema para cada tabela. Só tem de criar um único modelo e fornecer diferentes sufixos para que o BigQuery possa criar as novas tabelas por si. O BigQuery coloca as tabelas no mesmo projeto e conjunto de dados.

Normalmente, as tabelas criadas através de tabelas de modelos ficam disponíveis em poucos segundos. Em casos raros, podem demorar mais tempo a ficar disponíveis.

Altere o esquema da tabela de modelos

Se alterar o esquema de uma tabela de modelo, todas as tabelas geradas posteriormente usam o esquema atualizado. As tabelas geradas anteriormente não são afetadas, a menos que a tabela existente ainda tenha um buffer de streaming.

Para tabelas existentes que ainda tenham um buffer de streaming, se modificar o esquema da tabela de modelo de forma retrocompatível, o esquema dessas tabelas geradas com streaming ativo também é atualizado. No entanto, se modificar o esquema da tabela de modelos de forma não compatível com versões anteriores, todos os dados em buffer que usam o esquema antigo são perdidos. Além disso, não pode transmitir novos dados para tabelas geradas existentes que usem o esquema antigo, mas agora incompatível.

Depois de alterar o esquema de uma tabela de modelos, aguarde até que as alterações sejam propagadas antes de tentar inserir novos dados ou consultar as tabelas geradas. Os pedidos de inserção de novos campos devem ser bem-sucedidos dentro de alguns minutos. As tentativas de consultar os novos campos podem exigir um tempo de espera mais longo, até 90 minutos.

Se quiser alterar o esquema de uma tabela gerada, não altere o esquema até que o streaming através da tabela de modelos tenha parado e a secção de estatísticas de streaming da tabela gerada esteja ausente da resposta tables.get(), o que indica que não existem dados em buffer na tabela.

As tabelas particionadas e as tabelas agrupadas não sofrem das limitações anteriores e são o mecanismo recomendado.

Detalhes da tabela de modelos

Valor do sufixo do modelo
O valor templateSuffix (ou --template_suffix) tem de conter apenas letras (a-z, A-Z), números (0-9) ou sublinhados (_). O comprimento combinado máximo do nome da tabela e do sufixo da tabela é de 1024 carateres.
Quota

As tabelas de modelos estão sujeitas a limitações de quota de streaming. O seu projeto pode criar até 10 tabelas por segundo com tabelas de modelos, semelhantes à API tables.insert. Esta quota aplica-se apenas às tabelas que estão a ser criadas e não às tabelas que estão a ser modificadas.

Se a sua aplicação precisar de criar mais de 10 tabelas por segundo, recomendamos a utilização de tabelas agrupadas. Por exemplo, pode colocar o ID da tabela de alta cardinalidade na coluna de chave de uma única tabela de agrupamento.

Tempo de vida

A tabela gerada herda o respetivo tempo de expiração do conjunto de dados. Tal como acontece com os dados de streaming normais, não é possível copiar imediatamente as tabelas geradas.

Remoção de duplicados

A eliminação de duplicados só ocorre entre referências uniformes a uma tabela de destino. Por exemplo, se transmitir simultaneamente para uma tabela gerada usando tabelas de modelos e um comando insertAll normal, não ocorre desduplicação entre as linhas inseridas pelas tabelas de modelos e um comando insertAll normal.

Visualizações

A tabela de modelos e as tabelas geradas não devem ser vistas.

Resolva problemas de inserções de streaming

As secções seguintes abordam a resolução de problemas de erros que ocorrem quando faz stream de dados para o BigQuery através da API Legacy Streaming. Para mais informações sobre como resolver erros de quota para inserções de streaming, consulte Erros de quota de inserções de streaming.

Códigos de resposta HTTP de falha

Se receber um código de resposta HTTP de falha, como um erro de rede, não existe forma de saber se a inserção de streaming foi bem-sucedida. Se tentar reenviar o pedido, pode acabar com linhas duplicadas na tabela. Para ajudar a proteger a sua tabela contra duplicações, defina a propriedade insertId quando enviar o seu pedido. O BigQuery usa a propriedade insertId para remover duplicações.

Se receber um erro de autorização, um erro de nome de tabela inválido ou um erro de quota excedida, não são inseridas linhas e todo o pedido falha.

Códigos de resposta HTTP de êxito

Mesmo que receba um código de resposta HTTP com êxito, tem de verificar a propriedade insertErrors da resposta para determinar se as inserções de linhas foram bem-sucedidas, uma vez que é possível que o BigQuery só tenha tido êxito parcial na inserção das linhas. Pode encontrar um dos seguintes cenários:

  • Todas as linhas foram inseridas com êxito. Se a propriedade insertErrors for uma lista vazia, todas as linhas foram inseridas com êxito.
  • Algumas linhas foram inseridas com êxito. Exceto nos casos em que existe uma incompatibilidade de esquema em qualquer uma das linhas, as linhas indicadas na propriedade insertErrors não são inseridas, e todas as outras linhas são inseridas com êxito. A propriedade errors contém informações detalhadas sobre o motivo da falha de cada linha sem êxito. A propriedade index indica o índice da linha com base em 0 do pedido ao qual o erro se aplica.
  • Nenhuma das linhas foi inserida com êxito. Se o BigQuery encontrar uma incompatibilidade de esquema em linhas individuais no pedido, nenhuma das linhas é inserida e é devolvida uma entrada insertErrors para cada linha, mesmo as linhas que não tinham uma incompatibilidade de esquema. As linhas que não tinham uma incompatibilidade de esquema têm um erro com a propriedade reason definida como stopped e podem ser reenviadas tal como estão. As linhas que falharam incluem informações detalhadas sobre a incompatibilidade de esquema. Para saber mais acerca dos tipos de protocolo buffer suportados para cada tipo de dados do BigQuery, consulte Conversões de tipos de dados.

Erros de metadados para inserções de streaming

Uma vez que a API de streaming do BigQuery foi concebida para taxas de inserção elevadas, as modificações aos metadados da tabela subjacente são eventualmente consistentes quando interagem com o sistema de streaming. Na maioria das vezes, as alterações aos metadados são propagadas em poucos minutos, mas durante este período, as respostas da API podem refletir o estado inconsistente da tabela.

Alguns cenários incluem:

  • Alterações ao esquema. A modificação do esquema de uma tabela que recebeu recentemente inserções de streaming pode causar respostas com erros de incompatibilidade de esquemas, porque o sistema de streaming pode não detetar imediatamente a alteração do esquema.
  • Criação/eliminação de tabelas. O streaming para uma tabela inexistente devolve uma variação de uma resposta notFound. Uma tabela criada na resposta pode não ser reconhecida imediatamente por inserções de streaming subsequentes. Da mesma forma, a eliminação ou a recriação de uma tabela pode criar um período em que as inserções de streaming são efetivamente enviadas para a tabela antiga. As inserções de streaming podem não estar presentes na nova tabela.
  • Truncatura de tabelas. A truncagem dos dados de uma tabela (através de uma tarefa de consulta que usa writeDisposition de WRITE_TRUNCATE) pode, de igual modo, fazer com que as inserções subsequentes durante o período de consistência sejam ignoradas.

Dados em falta/indisponíveis

As inserções de streaming residem temporariamente no armazenamento otimizado para escrita, que tem características de disponibilidade diferentes do armazenamento gerido. Determinadas operações no BigQuery não interagem com o armazenamento otimizado para escrita, como tarefas de cópia de tabelas e métodos de API como tabledata.list. Os dados de streaming recentes não estão presentes na tabela de destino nem na saída.