Sardine named a Leader in The Forrester Wave™: Financial Crime Management Solutions, Q3 2026

Learn More

Publicación del conversor de protobuf a BigQuery como código abierto

Kazuki Nishiura
Kazuki Nishiura
bg-image
bg-image
Publicación del conversor de protobuf a BigQuery como código abierto
Subscribe to newsletter
Share

En Sardine usamos protocol buffers (protobuf) en todas partes. Es un formato de serialización ligero, neutral en cuanto al lenguaje y con tipado.

Usamos protobuf para definir el esquema de datos de la tabla de BigQuery y también para generar el código del servidor backend (Go) a partir del mismo archivo protobuf. Nuestros servidores backend rellenan la estructura de Go (generada desde protobuf), la envían a Pub/Sub y luego los jobs de Dataflow la consumen en BigQuery.

Imagen

Este sencillo patrón funcionó bastante bien con una salvedad. Cuando empezamos, no había una solución clara sobre cómo convertir un objeto de Pub/Sub en una inserción de fila de BigQuery, así que tuvimos que escribir código repetitivo como el siguiente para copiar datos de un objeto a otro:

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

Esto era muy tedioso y propenso a errores. Cuando añadíamos un nuevo campo en la tabla de BigQuery, también teníamos que actualizar el código repetitivo anterior. Debe de haber una mejor solución para esto.

(nota al margen: si hoy empiezas un nuevo servicio, podrías usar JSON en lugar de protobuf como formato de serialización para pubsub y luego usar la plantilla oficial (beta) de Google para trabajos de pubsub a bigquery —https://cloud.google.com/dataflow/docs/guides/templates/provided-streaming)

Resulta que puedes iterar dinámicamente sobre un objeto protobuf, así que en lugar de codificar los nombres de los campos, podríamos hacer lo siguiente:

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;...

Eso es todo. Redujo nuestro código boilerplate y ahora ya no tenemos que preocuparnos por actualizar el código Java (ten en cuenta que aún necesitas volver a desplegar el job de Dataflow ante cualquier cambio de esquema para que el ejecutor del job conozca la última definición del proto).

Hicimos público el código en el siguiente repositorio para que la comunidad no tenga que reinventar la rueda — https://github.com/sardine-ai/proto-to-bq-java

Si tienes algún comentario, por favor ponte en contacto conmigo https://twitter.com/kazukinishiura

Estamos contratando para todos los puestos de ingeniería — https://www.sardine.ai/careers