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

Learn More
Engineering

protobufからBigQueryへのコンバーターをオープンソース化

Kazuki Nishiura
Kazuki Nishiura
bg-image
bg-image
protobufからBigQueryへのコンバーターをオープンソース化
Subscribe to newsletter
Share

Sardineでは、あらゆる場面でprotocol buffers(protobuf)を使用しています。これは、軽量で言語に依存しない、型付きのシリアライゼーション形式です。

protobufを使ってBigQueryテーブルのデータスキーマを定義し、同じprotobufファイルからバックエンドサーバー(go)のコードも生成しています。バックエンドサーバーは(protobufから生成された)golangのstructにデータを入れてpubsubに送信し、その後dataflowジョブがそれをBigQueryに取り込みます。

Image

このシンプルなパターンはうまく機能しましたが、一つ注意点がありました。開始当初、pubsubオブジェクトをBigQueryの行挿入に変換する明確な方法がなかったため、あるオブジェクトから別のオブジェクトへデータをコピーするために、以下のような定型コードを書く必要がありました。

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

これは非常に手間がかかり、ミスも起きやすいものでした。BigQueryテーブルに新しいフィールドを追加するたびに、上記の定型コードも更新する必要がありました。もっと良い方法があるはずでした。

(補足: もし今日新しいサービスを立ち上げるなら、pubsubのシリアライゼーション形式としてprotobufの代わりにJSONを使い、Google公式のpubsub-to-bigqueryジョブテンプレート(ベータ版)を使うという選択肢もあります —https://cloud.google.com/dataflow/docs/guides/templates/provided-streaming)

実はprotobufオブジェクトは動的にイテレートできることが分かったため、フィールド名をハードコーディングする代わりに、以下のようにすることができました。

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

これだけです!これにより定型コードが削減され、Javaコードを更新する心配がなくなりました(なお、スキーマを変更した場合は、ジョブランナーが最新のproto定義を認識できるように、dataflowジョブを再デプロイする必要があります)

コミュニティが車輪の再発明をしなくて済むように、以下のリポジトリでコードを公開しました — https://github.com/sardine-ai/proto-to-bq-java

ご意見・ご感想がありましたら、こちらまでお気軽にご連絡ください https://twitter.com/kazukinishiura

現在、あらゆるエンジニアリング職種で採用を行っています — https://www.sardine.ai/careers