テクニック

Protocol Buffers を扱う上で一般的に使用される設計パターンについて説明します。

設計や使用方法に関する質問は、Protocol Buffers ディスカッション グループに送ることもできます。

一般的なファイル名サフィックス

複数の異なるフォーマットでメッセージをファイルに書き込むことはかなり一般的です。これらのファイルには以下のファイル拡張子を使用することをお勧めします。

内容拡張子
テキスト形式.txtpb
ワイヤー形式.binpb
JSON 形式.json

特にテキスト形式では、.textproto もかなり一般的ですが、簡潔さのためには .txtpb をお勧めします。

複数のメッセージのストリーミング

複数のメッセージを1つのファイルまたはストリームに書き込む場合、あるメッセージがどこで終わり、次のメッセージがどこで始まるかを追跡するのはあなた次第です。Protocol Buffer のワイヤー形式は自己区切りではないため、プロトコルバッファパーサーはメッセージの終わりを単独で判断できません。この問題を解決する最も簡単な方法は、メッセージ自体を書き込む前に各メッセージのサイズを書き込むことです。メッセージを読み戻す際には、まずサイズを読み取り、次にバイトを別のバッファに読み込み、そのバッファからパースします。(バイトを別のバッファにコピーするのを避けたい場合は、CodedInputStream クラス(C++とJavaの両方で利用可能)を調べてみてください。これは、特定のバイト数に読み取りを制限するように指示できます。)

大規模なデータセット

Protocol Buffers は、大規模なメッセージを処理するように設計されていません。一般的な経験則として、各メッセージが1メガバイトを超える場合は、代替の戦略を検討する時期かもしれません。

とはいえ、Protocol Buffers は大規模なデータセットの個々のメッセージを処理するのに非常に優れています。通常、大規模なデータセットは小さな断片の集まりであり、各小さな断片は構造化されたデータです。Protocol Buffers はセット全体を一度に処理することはできませんが、各断片をエンコードするために Protocol Buffers を使用すると、問題が大幅に簡素化されます。これで、構造のセットではなく、バイト列のセットを扱うだけで済みます。

Protocol Buffers は、大規模なデータセットに対する組み込みのサポートを含んでいません。これは、状況によって異なる解決策が求められるためです。単純なレコードのリストで十分な場合もあれば、データベースのようなものが求められる場合もあります。各ソリューションは個別のライブラリとして開発されるべきであり、そうすることで、必要な人だけがそのコストを支払えばよくなります。

自己記述型メッセージ

Protocol Buffers は、自身の型の記述を含んでいません。したがって、その型を定義する対応する .proto ファイルがない生のメッセージだけを与えられた場合、有用なデータを抽出することは困難です。

しかし、.proto ファイルの内容自体もプロトコルバッファを使用して表現できます。ソースコードパッケージ内のファイル src/google/protobuf/descriptor.proto は、関連するメッセージ型を定義しています。protoc--descriptor_set_out オプションを使用して、.proto ファイルのセットを表す FileDescriptorSet を出力できます。これにより、以下のように自己記述型プロトコルメッセージを定義できます。

syntax = "proto3";

import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";

message SelfDescribingMessage {
  // Set of FileDescriptorProtos which describe the type and its dependencies.
  google.protobuf.FileDescriptorSet descriptor_set = 1;

  // The message and its type, encoded as an Any message.
  google.protobuf.Any message = 2;
}

DynamicMessage(C++ および Java で利用可能)のようなクラスを使用することで、SelfDescribingMessage を操作できるツールを作成できます。

とは言え、この機能が Protocol Buffer ライブラリに含まれていない理由は、Google 社内でこれまでこれを使用する必要がなかったからです。

このテクニックでは、ディスクリプタを使用した動的メッセージのサポートが必要です。自己記述型メッセージを使用する前に、お使いのプラットフォームがこの機能をサポートしていることを確認してください。