Neste documento, descrevemos como fazer streaming de dados no BigQuery usando o
método tabledata.insertAll
legado.
Para novos projetos, recomendamos usar a
API BigQuery Storage Write em vez do
método tabledata.insertAll
. A API Storage Write tem preços
mais baixos e recursos mais robustos, incluindo semântica de entrega apenas uma vez. Se
você estiver migrando um projeto atual do método tabledata.insertAll
para a API Storage Write, recomendamos selecionar o
fluxo padrão. O
método tabledata.insertAll
ainda é totalmente compatível.
Antes de começar
Verifique se você tem acesso de gravação ao conjunto de dados que contém a tabela de destino. A tabela precisa existir antes de você começar a gravar dados nela, a menos que você esteja usando tabelas de modelo. Para mais informações sobre tabelas de modelo, consulte Criação automática de tabelas usando tabelas de modelo.
Verifique a política de cotas para dados de streaming.
-
Verifique se a cobrança está ativada para o seu projeto do Google Cloud.
Atribua papéis do Identity and Access Management (IAM) que concedam aos usuários as permissões necessárias para realizar cada tarefa deste documento.
O streaming não está disponível pelo nível gratuito. Se tentar usar o streaming sem ativar o faturamento, este erro será exibido: BigQuery: Streaming insert is not allowed in the free tier.
Permissões necessárias
Para fazer o streaming de dados no BigQuery, você precisa das seguintes permissões do IAM:
bigquery.tables.updateData
(permite inserir dados na tabela)bigquery.tables.get
(permite receber metadados da tabela)bigquery.datasets.get
(permite receber metadados do conjunto de dados)bigquery.tables.create
(obrigatório se você usar uma tabela de modelo para criar a tabela automaticamente)
Todos estes papéis predefinidos do IAM incluem as permissões necessárias para fazer streaming de dados no BigQuery:
roles/bigquery.dataEditor
roles/bigquery.dataOwner
roles/bigquery.admin
Para mais informações sobre os papéis e as permissões do IAM no BigQuery, consulte Papéis e permissões predefinidos.
Fazer streaming de dados para o BigQuery
C#
Antes de testar esta amostra, siga as instruções de configuração do 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#.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Go
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Java
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Node.js
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
PHP
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Python
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Ruby
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Não é necessário preencher o campo insertID
ao inserir linhas.
O exemplo a seguir mostra como evitar o envio de um insertID
para cada linha
durante o streaming.
Java
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Python
Antes de testar esta amostra, siga as instruções de configuração do 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.
Para autenticar no BigQuery, configure o Application Default Credentials. Para mais informações, acesse Configurar a autenticação para bibliotecas de cliente.
Enviar dados de data e hora
Para campos de data e hora, formate os dados no método tabledata.insertAll
desta
maneira:
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 1970-01-01 (a época do Unix) ou uma string no formato "YYYY-MM-DD HH:MM[:SS]" |
Enviar dados do 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 ausentes ou NULL para os campos start
e end
representam limites ilimitados.
Esses campos precisam ter o mesmo formato JSON compatível do tipo T
, em que
T
pode ser DATE
, DATETIME
ou TIMESTAMP
.
No exemplo a seguir, o campo f_range_date
representa uma coluna RANGE<DATE>
em uma tabela. Uma linha é inserida nessa coluna usando a
API tabledata.insertAll
.
{
"f_range_date": {
"start": "1970-01-02",
"end": null
}
}
Disponibilidade de dados de streaming
Os dados ficam disponíveis para análise em tempo real por consultas do GoogleSQL imediatamente
depois que o BigQuery reconhece uma
solicitação tabledata.insertAll
.
As linhas transmitidas recentemente para uma tabela particionada por tempo de processamento têm temporariamente um valor NULL para a pseudocoluna _PARTITIONTIME
. Para essas linhas, o BigQuery atribui o valor final NULL da coluna PARTITIONTIME
em segundo plano, normalmente em alguns minutos. Em casos raros, isso pode levar até 90 minutos.
Algumas linhas transmitidas recentemente podem não estar disponíveis para cópia da tabela normalmente por
alguns minutos. Em casos raros, isso pode levar até 90 minutos. Para ver se os dados
estão disponíveis para cópia, verifique se, na resposta tables.get
, existe uma seção denominada
streamingBuffer
.
Se a seção streamingBuffer
não estiver presente, seus dados estarão disponíveis para cópia.
Também é possível usar o campo streamingBuffer.oldestEntryTime
para identificar a
idade dos registros no buffer de streaming.
Eliminação de duplicação por melhor esforço
Quando você fornece insertId
para uma linha inserida, o BigQuery usa esse ID para aceitar a eliminação de duplicação por melhor esforço por até um minuto. Ou seja, se
você transmitir a mesma linha com o mesmo insertId
mais de uma vez nesse
período na mesma tabela, o BigQuery pode eliminar a duplicação
de várias ocorrências dessa linha, mantendo apenas uma dessas ocorrências.
O sistema espera que as linhas fornecidas com insertId
s idênticos também sejam
idênticas. Se duas linhas tiverem insertId
s idênticos, o BigQuery vai preservar uma delas por
um processo não determinístico.
A eliminação da duplicação costuma se destinar a cenários de nova tentativa em um sistema distribuído em que
não é possível determinar o estado de uma inserção por streaming sob determinadas condições de
erro. Esses erros podem ser de rede entre o sistema e o BigQuery
ou internos do BigQuery.
Se você tentar novamente uma inserção, use o mesmo insertId
para o mesmo conjunto de linhas e o BigQuery tentará eliminar a duplicação dos seus dados. Para mais informações, consulte solução de problemas com inserções de streaming.
A eliminação de duplicação feita pelo BigQuery é o melhor esforço possível e não pode ser considerado um mecanismo para garantir a ausência de cópias nos dados. Além disso, o BigQuery pode prejudicar a qualidade da eliminação de duplicação por melhor esforço a qualquer momento para garantir maior confiabilidade e disponibilidade dos dados.
Se você tem requisitos rígidos de eliminação de duplicação para os dados, o Google Cloud Datastore é um serviço alternativo compatível com transações.
Como desativar a eliminação de duplicação por melhor esforço
É possível desativar a eliminação de duplicação por melhor esforço ao não preencher o campo insertId
de cada linha inserida. Essa é a maneira recomendada de inserir dados.
Apache Beam e Dataflow
Para desativar a eliminação de duplicação por melhor esforço ao usar o conector de E/S do BigQuery do Apache Beam para Java, use o método ignoreInsertIds()
.
Remoção manual de duplicatas
Para garantir que não existam linhas duplicadas depois do término do streaming, use o seguinte processo manual:
- Adicione
insertId
como uma coluna no esquema da tabela e inclua o valorinsertId
nos dados de cada linha. - Após o streaming ser interrompido, execute a seguinte consulta para verificar se há duplicatas:
Se o resultado for maior que 1, existem duplicatas.#standardSQL SELECT MAX(count) FROM( SELECT ID_COLUMN, count(*) as count FROM `TABLE_NAME` GROUP BY ID_COLUMN)
- Para remover as duplicatas, execute a seguinte consulta. Especifique
uma tabela de destino, permita resultados grandes e desative o achatamento 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
Observações sobre a consulta de remoção de duplicatas:
- A estratégia mais segura para a consulta de remoção de duplicatas é direcionar para uma nova tabela.
Outra opção é direcionar para a tabela de origem com a disposição de gravação
WRITE_TRUNCATE
. - A consulta de remoção de duplicatas adiciona uma coluna
row_number
, com o valor1
, ao final do esquema da tabela. A consulta usa uma instruçãoSELECT * EXCEPT
do GoogleSQL para excluir a colunarow_number
da tabela de destino. O prefixo#standardSQL
ativa o GoogleSQL para essa consulta. Outra opção é selecionar por nomes de coluna específicos para omitir essa coluna. - Para consultar dados ativos com duplicatas removidas, também é possível criar uma visualização sobre a tabela usando a consulta de remoção de duplicatas. Lembre-se de que os custos de consulta com a visualização serão calculados com base nas colunas selecionadas. Isso pode resultar em grandes tamanhos verificados de bytes.
Fazer streaming em tabelas particionadas por tempo
Quando você faz stream de dados para uma tabela particionada por tempo, cada partição tem um buffer
de streaming. O buffer de streaming é mantido quando você executa um job
de carregamento, consulta ou cópia que substitui uma partição ao definir a propriedade writeDisposition
como
WRITE_TRUNCATE
. Se quiser remover o buffer de streaming, verifique se ele
está vazio chamando
tables.get
na partição.
Particionamento por tempo de processamento
Ao fazer streaming para uma tabela particionada por tempo de processamento, o BigQuery infere a partição de destino a partir da hora UTC atual.
Os dados recém-recebidos são colocados temporariamente na partição __UNPARTITIONED__
enquanto estão no buffer de streaming. Quando há dados não particionados suficientes,
o BigQuery particiona os dados na partição correta. No entanto, não há SLA sobre o prazo necessário para os dados serem movidos da partição __UNPARTITIONED__
. Uma consulta pode excluir dados do buffer de streaming de uma consulta, filtrando os valores NULL
da partição __UNPARTITIONED__
usando uma das pseudocolunas ([_PARTITIONTIME
] ou [_PARTITIONDATE
], dependendo do tipo de dados preferido).
Se estiver fazendo streaming de dados para uma tabela particionada diária, é possível substituir
a inferência de data fornecendo um decorador de partição como parte da solicitação
insertAll
. Inclua o decorador no parâmetro tableId
. Por exemplo, é possível
fazer o streaming para a partição correspondente a 01-03-2021 para a tabela table1
usando o
decorador de partições:
table1$20210301
É possível fazer streaming usando um decorador de partições para partições dos últimos 31 dias e dos próximos 16 dias em relação à data atual, com base na hora UTC atual. Para gravar em partições de datas fora desses limites permitidos, use um job de carregamento ou de consulta, como descrito em Como anexar e substituir dados da tabela particionada.
O streaming usando um decorador de partição só é compatível com tabelas particionadas por dia. Ele não é compatível com tabelas particionadas por hora, mês ou ano.
Para testar, use o comando da CLI bq insert
da ferramenta de linha de comando bq.
Por exemplo, o comando a seguir transmite de uma única linha para uma partição de 1º de janeiro de 2017 ($20170101
) em uma tabela particionada denominada mydataset.mytable
:
echo '{"a":1, "b":2}' | bq insert 'mydataset.mytable$20170101'
Particionamento de colunas por unidade de tempo
É possível fazer streaming de dados em uma tabela particionada em uma coluna DATE
, DATETIME
ou
TIMESTAMP
que esteja entre os últimos cinco anos e o próximo ano.
Dados fora desse intervalo são rejeitados.
Quando os dados são transmitidos, eles são inicialmente colocados na partição
__UNPARTITIONED__
. Quando há dados não particionados suficientes, o BigQuery
os particiona automaticamente, colocando-os na partição apropriada.
No entanto, não há SLA sobre o prazo necessário para os dados serem movidos da partição __UNPARTITIONED__
.
- Observação: partições diárias são processadas de maneira diferente das partições por hora, mensais e anuais. Somente os dados fora do período (últimos sete dias a três dias futuros) são extraídos para a partição NÃO PARTICIONADA, aguardando para serem particionados novamente. Por outro lado, para tabela particionada por hora, os dados são sempre extraídos para a partição NÃO PARTICIONADA e, posteriormente, reparticionadas.
Criar tabelas automaticamente usando tabelas de modelo
As tabelas de modelo fornecem um mecanismo para dividir uma tabela lógica em muitas tabelas menores para criar conjuntos menores de dados (por exemplo, por ID do usuário). As tabelas de modelo têm várias limitações, conforme descrito abaixo. Já as tabelas particionadas e em cluster são as maneiras recomendadas de conseguir esse comportamento.
Para usar uma tabela de modelo com a API BigQuery, adicione um parâmetro templateSuffix
à solicitação insertAll
. Na ferramenta de linha de comando bq, adicione a sinalização template_suffix
ao comando insert
. Se o BigQuery detectar um parâmetro
templateSuffix
ou a sinalização template_suffix
, ele tratará a tabela visada como um modelo
base. Ela cria uma nova tabela que compartilha o mesmo esquema da tabela
visada e tem um nome que inclui o sufixo especificado:
<targeted_table_name> + <templateSuffix>
Ao usar uma tabela de modelo, você evita a sobrecarga de criar cada tabela individualmente e especificar o esquema para cada tabela. Você só precisa criar um modelo único e fornecer sufixos diferentes para que o BigQuery possa criar as tabelas novas para você. O BigQuery coloca as tabelas no mesmo projeto e conjunto de dados.
As tabelas criadas com as tabelas de modelo geralmente ficam disponíveis em alguns segundos. Em raras ocasiões, elas podem levar mais tempo para ficarem disponíveis.
Alterar o esquema da tabela de modelo
Se você alterar um esquema de tabelas de modelo, todas as tabelas geradas posteriormente usarão o esquema atualizado. As tabelas geradas anteriormente não são afetadas, a menos que a tabela ainda tenha um buffer de streaming.
Se você modificar o esquema de tabelas de modelo de uma maneira compatível com versões anteriores para tabelas que ainda têm um buffer de streaming, o esquema dessas tabelas geradas com streaming ativo também será atualizado. No entanto, se você modificar o esquema de tabelas de modelo de uma maneira não compatível com versões anteriores, todos os dados armazenados em buffer que usam o esquema antigo serão perdidos. Além disso, não é possível fazer streaming de novos dados para as tabelas geradas que usam o esquema antigo, mas agora incompatível.
Depois de alterar um esquema de tabelas de modelo, aguarde até que as alterações se propaguem antes de tentar inserir novos dados ou consultar tabelas geradas. As solicitações para inserir novos campos devem ficar prontas em poucos minutos. As tentativas de consulta dos novos campos podem exigir uma espera mais longa, de até 90 minutos.
Caso seja necessário alterar o esquema de uma tabela gerada, não altere o
esquema até que o streaming da tabela de modelo seja interrompido e a seção
de estatísticas do streaming da tabela esteja ausente da resposta tables.get()
,
indicando que nenhum dado está armazenado em buffer na tabela.
As tabelas particionadas e em cluster não apresentam as limitações acima e são o mecanismo recomendado.
Detalhes da tabela de modelo
- Valor do sufixo do modelo
- O valor
templateSuffix
(ou--template_suffix
) precisa conter apenas letras (a-z, A-Z), números (0-9) ou sublinhados (_). O tamanho máximo combinado do nome e do sufixo da tabela é de 1.024 caracteres. - Cota
As tabelas de modelo estão sujeitas a limitações de cota de streaming. Seu projeto pode criar até 10 tabelas por segundo com tabelas de modelos, semelhante à API
tables.insert
. Essa cota se aplica somente às tabelas que estão sendo criadas, não às tabelas que estão sendo modificadas.Se o aplicativo precisar criar mais de 10 tabelas por segundo, recomendamos o uso de tabelas em cluster. Por exemplo, é possível colocar o ID da tabela de alta cardinalidade na coluna-chave de uma única tabela de clustering.
- Tempo para ficar ativa
A tabela gerada herda o tempo de expiração do conjunto de dados. Como acontece com os dados de streaming normais, as tabelas geradas não podem ser copiadas imediatamente.
- Desduplicação
A desduplicação só acontece entre referências uniformes a uma tabela de destino. Por exemplo, ao fazer streaming simultâneo para uma tabela gerada usando tabelas de modelo e um comando
insertAll
normal, nenhuma eliminação de duplicação ocorrerá entre linhas inseridas por tabelas de modelo e um comandoinsertAll
normal.- Visualizações
A tabela de modelo e as tabelas geradas não devem ser visualizadas.
Resolver problemas de inserções por streaming
As seções a seguir explicam como resolver erros que ocorrem quando você faz streaming de dados para o BigQuery usando a API de streaming legada. Para mais informações sobre como resolver erros de cota para inserções por streaming, consulte Erros de cota de inserção por streaming.
Códigos de resposta HTTP de falha
Se você receber um código de resposta HTTP de falha, como um erro de rede, não será possível saber se a inserção de streaming foi bem-sucedida. Se você tentar reenviar a solicitação, você acabará com linhas duplicadas na tabela. Para ajudar a proteger a tabela contra duplicação, defina a property insertId
ao enviar a solicitação. O BigQuery usa a property insertId
para remoção da duplicação.
Se você receber um erro de permissão, de nome de tabela inválido ou de cota excedida, nenhuma linha será inserida, e a solicitação inteira falhará.
Códigos de resposta HTTP de sucesso
Mesmo que você receba um
código de resposta HTTP de sucesso, será necessário verificar
a property insertErrors
da resposta para determinar se as inserções de linha foram
bem-sucedidas, porque é possível que o BigQuery tenha conseguido inserir
as linhas apenas parcialmente. Você pode encontrar um dos seguintes cenários:
- Todas as linhas foram inseridas com sucesso. Se a property
insertErrors
for uma lista vazia, todas as linhas foram inseridas com sucesso. - Algumas linhas foram inseridas com sucesso. Exceto nos casos em que houver uma
incompatibilidade de esquema em qualquer uma das linhas, as linhas indicadas na propriedade
insertErrors
não serão inseridas e todas as outras linhas serão inseridas com sucesso. A propertyerrors
contém informações detalhadas sobre o motivo de falha de cada linha malsucedida. A propertyindex
indica o índice de linha com base em 0 da solicitação à qual o erro se aplica. - Nenhuma das linhas foi inserida com sucesso. Se o BigQuery encontrar uma
incompatibilidade de esquema em linhas individuais na solicitação, nenhuma das linhas será inserida e uma
entrada
insertErrors
será retornada para cada linha, mesmo as linhas que não tiveram incompatibilidade de esquema. As linhas que não tiveram incompatibilidade de esquema terão um erro com a propriedadereason
definida comostopped
e podem ser reenviadas como estão. As linhas que falharam exibem informações detalhadas sobre a incompatibilidade de esquema. Para saber mais sobre os tipos de buffer de protocolo compatíveis com cada tipo de dado do BigQuery, consulte Conversões de tipo de dado.
Erros de metadados para inserções de streaming
Como a API de streaming do BigQuery foi projetada para altas taxas de inserção, as modificações na exibição de metadados da tabela subjacente têm consistência eventual durante a interação com o sistema de streaming. Na maioria das vezes, as alterações de metadados são propagadas em minutos. No entanto, durante esse período, as respostas da API podem refletir o estado inconsistente da tabela.
Alguns cenários incluem:
- Mudanças no esquema. A modificação do esquema de uma tabela que recebeu inserções de streaming recentemente pode causar respostas com erros de incompatibilidade de esquema, porque o sistema de streaming pode não captar imediatamente a alteração de esquema.
- Criação/exclusão de tabela. Fazer streaming para uma tabela que não existe retorna uma variação de uma resposta
notFound
. Uma tabela criada em resposta pode não ser reconhecida imediatamente pelas inserções de streaming subsequentes. Da mesma forma, excluir ou recriar uma tabela pode criar um período em que as inserções de streaming são entregues efetivamente à tabela antiga. As inserções de streaming podem não estar presentes na nova tabela. - Truncamento da tabela. Truncar os dados de uma tabela (por meio de um job de consulta que usa writeDisposition de WRITE_TRUNCATE) pode causar a eliminação de inserções subsequentes durante o período de consistência.
Dados ausentes/não disponíveis
As inserções por streaming ficam temporariamente no armazenamento otimizado para gravação, que tem características de disponibilidade
diferentes do armazenamento gerenciado. Algumas operações no BigQuery não interagem
com o armazenamento otimizado para gravação, como jobs de cópia de tabela e métodos de API, como tabledata.list
.
Os dados de streaming recentes não estarão presentes na tabela de destino ou na saída.