SardineCon SF/2026

Learn More

Abrindo o código-fonte do conversor protobuf-para-bigquery

Kazuki Nishiura
Kazuki Nishiura
bg-image
bg-image
Abrindo o código-fonte do conversor protobuf-para-bigquery
Subscribe to newsletter
Share

Na Sardine usamos protocol buffers (protobuf) em toda parte. É um formato de serialização leve, independente de linguagem e com tipagem.

Usamos protobuf para definir o esquema de dados da tabela do BigQuery e também gerar o código do servidor backend em Go a partir do mesmo arquivo protobuf. Nossos servidores backend preenchem a struct em Go (gerada a partir do protobuf), a enviam para o Pub/Sub e, em seguida, jobs do Dataflow a consomem no BigQuery.

Imagem

Esse padrão simples funcionou muito bem, com uma ressalva. Quando começamos, não havia uma solução clara de como converter um objeto pubsub em uma inserção de linha no BigQuery, então precisávamos escrever código boilerplate como o abaixo para copiar dados de um objeto para outro:

TableRow clientMetadataRow = new TableRow() .set("session_key", clientMetadata.getSessionKey()) .set("client_id", clientMetadata.getClientId()) .set("revision", clientMetadata.getRevision()) .set("user_id", clientMetadata.getUserId())...

Isso era muito trabalhoso e sujeito a erros. Quando adicionávamos um novo campo na tabela do BigQuery, também precisávamos atualizar o código boilerplate acima. Deve haver uma solução melhor para isso.

(observação — se você iniciar um novo serviço hoje, pode usar JSON em vez de protobuf como formato de serialização para o pubsub e então usar o template oficial (beta) de job pubsub-to-bigquery do Google —https://cloud.google.com/dataflow/docs/guides/templates/provided-streaming)

Acontece que você pode iterar dinamicamente sobre o objeto protobuf, então em vez de codificar os nomes dos campos manualmente, poderíamos fazer o seguinte:

void copyFields(GeneratedMessageV3 fromProto, TableRow toRow) { allFields = fromProto.getDescriptorForType().getFields(); for (Descriptors.FieldDescriptor field: allFields) { Object value = fields.get(field); String columnName = field.getName(); switch (field.getJavaType()) { case STRING: if (value != null) { toRow.set(columnName, value); } break;...

É isso! Isso reduziu o nosso código boilerplate e agora não precisamos mais nos preocupar em atualizar o código Java (observe que você ainda precisa fazer o redeploy do job do Dataflow para qualquer alteração de esquema, para que o executor do job conheça a definição mais recente do proto).

Tornamos o código público no repositório abaixo para que a comunidade não precise reinventar a roda — https://github.com/sardine-ai/proto-to-bq-java

Se você tiver qualquer feedback, por favor entre em contato comigo https://twitter.com/kazukinishiura

Estamos contratando para todas as funções de engenharia — https://www.sardine.ai/careers