プロトコル バッファでサポートされているリストに含まれていない一般的なデータ型を保存する最適な方法を知りたいです。
- 日時 (秒精度)
- datetime (ミリ秒の精度)
- 固定精度の小数
- 可変精度の小数
- 多数の bool 値 (それらが多数ある場合、それらのタグのために、それぞれに 1 ~ 2 バイトのオーバーヘッドがあるように見えます。
また、対応する C++/Python/Java データ型に非常に簡単にマップするという考え方もあります。
プロトコル バッファでサポートされているリストに含まれていない一般的なデータ型を保存する最適な方法を知りたいです。
また、対応する C++/Python/Java データ型に非常に簡単にマップするという考え方もあります。
プロトコル バッファに似たワイヤ プロトコルに関する私の経験に基づくいくつかのアイデアを次に示します。
日時 (秒精度)
datetime (ミリ秒の精度)
これら2つの答えは同じだと思います。通常、秒精度の場合は、より狭い範囲の数値を扱っているだけです。
sint64/sfixed64 を使用して、1970 年 1 月 1 日午前 0 時 GMT などのよく知られたエポックからのオフセットを秒/ミリ秒単位で格納します。これは、 Date オブジェクトがJava で内部的に表現される方法です。Python と C++ にも類似点があると確信しています。
タイム ゾーン情報が必要な場合は、日付/時刻を UTC で渡し、関連するタイム ゾーンを別の文字列フィールドとしてモデル化します。そのために、Olson Zoneinfo データベースの識別子を使用できます。これは、やや標準になっているためです。
このようにして、日付/時刻の標準的な表現が得られますが、適切なタイム ゾーンにローカライズすることもできます。
固定精度の小数
私が最初に考えたのは、Python の decimal パッケージから Decimal オブジェクトを構築する方法と同様の文字列を使用することです。数値表現に比べて効率が悪い可能性があると思います。
使用しているドメインによっては、より良い解決策があるかもしれません。たとえば、金銭的価値をモデリングしている場合、uint32/64 を使用して、分数ではなくセントで値を伝えることができるかもしれません。
このスレッドには、役立つ提案もいくつかあります。
可変精度の小数
Protocol Buffers は float/double スカラー型で既にこれをサポートしていませんか? 多分私はこの箇条書きを誤解しました。
とにかく、これらのスカラー型を回避する必要がある場合は、IEEE-754 を使用して uint32 または uint64 (それぞれ float と double) にエンコードできます。たとえば、JavaではFloat/Double オブジェクトからIEEE-754 表現を抽出したり、その逆を行うことができます。C++/Python にも同様のメカニズムがあります。
多くの bool 値 (それらがたくさんある場合、それらのタグのためにそれぞれに 1 ~ 2 バイトのオーバーヘッドがあるように見えます。
ネットワーク上の無駄なバイトが気になる場合は、ビットマスキング手法を使用して、多くのブール値を単一の uint32 または uint64 に圧縮できます。
Protocol Buffers にはファースト クラスのサポートがないため、これらの手法はすべて、エージェント間の紳士的な契約を少し必要とします。おそらく、「_dttm」や「_mask」などの命名規則をフィールドに使用すると、特定のフィールドにプロトコル バッファのデフォルトの動作を超える追加のエンコーディング セマンティクスがある場合の通信に役立ちます。
protobuf の設計原理は、将来的に新しい言語を採用しやすいように、データ型のサポートを可能な限り「ネイティブ」に保つことです。ビルド内のメッセージ タイプを提供できると思いますが、どこに線を引きますか?
私の解決策は、2 つのメッセージ タイプを作成することでした。
DateTime
TimeSpan
これは、私が C# のバックグラウンドを持っており、これらの型が当然のことと考えられているためです。
振り返ってみるTimeSpan
と、DateTime
やり過ぎだったかもしれませんが、h/m/s から s への変換、およびその逆の変換を回避する「安価な」方法でした。そうは言っても、次のようなユーティリティ関数を実装するのは簡単だったでしょう:
int TimeUtility::ToSeconds(int h, int m, int s)
Bklyn は、ネストされたメッセージにヒープ メモリが使用されることを指摘しました。場合によっては、これは明らかに非常に有効です。メモリがどのように使用されているかを常に認識しておく必要があります。しかし、それ以外の場合では、実装の容易さについてより心配している場合は、これはそれほど重要ではありません (これが Java/C# の哲学だと思います)。
protobuf で非組み込み型を使用することには、小さな欠点もありTextFormat::Printer
ます。表示形式を指定できないため、次のようになります。
my_datetime {
seconds: 10
minutes: 25
hours: 12
}
...一部の人にとっては冗長すぎます。とはいえ、秒単位で表すと読みにくくなります。
結論として、私は言います:
DateTime
など) を使用します。申し訳ありませんが、完全な答えではありませんが、「私も」です。
これは素晴らしい質問だと思います。自分自身に答えてもらいたいです。日時や (金融アプリケーションの場合) 固定小数点 10 進数などの基本的な型をネイティブに記述できないこと、またはそれらを言語指定またはユーザー定義の型にマップできないことは、私にとって本当に致命的です。多かれ少なかれ、ライブラリを使用できなくなりましたが、そうでなければ素晴らしいと思います。
プロト文法で独自の「DateTime」または「FixedPoint」メッセージを宣言することは、実際には解決策ではありません。プラットフォームの表現を生成されたオブジェクトとの間で手動で変換する必要があり、エラーが発生しやすいからです。さらに、これらのネストされたメッセージは、C++ のヒープ割り当てオブジェクトへのポインターとして格納されます。これは、基になる型が基本的に単なる 64 ビット整数である場合、非常に非効率的です。
具体的には、proto ファイルに次のようなものを書きたいと思います。
message Something {
required fixed64 time = 1 [cpp_type="boost::posix_time::ptime"];
required int64 price = 2 [cpp_type="fixed_point<int64_t, 4>"];
...
};
そして、シリアル化が機能するように、これらの型を fixed64 および int64 との間で変換するために必要な接着剤を提供する必要があります。多分adobe::promoteのようなものを通して?
ミリ秒単位の日時の場合int64
、日時が のを使用しましたYYYYMMDDHHMMSSmmm
。これにより、簡潔で読みやすくなり、驚くべきことに、非常に長く続きます。
10 進数については、byte[]
損失のないより良い表現がないことを知って、 を使用しました。