3

私は DataContractSerializer の使用の一部をプロトコル バッファのシリアル化 (具体的には protobuf-net を使用) に切り替えて、シリアル化を高速化し、データベース BLOB に格納するためのシリアル化されたデータ サイズを小さくしています。

オブジェクト モデルを変更すると、メッセージ サイズに大きな影響があることがわかりました。これは、選択したオブジェクト モデルが原因でシリアル化されたデータが人為的に膨らんでいることを意味すると考えており、それを修正したいと考えています。

特に私の質問は、protobuf-net の使用法、またはシリアライゼーション ライブラリを変更して、メッセージ サイズを小さくすることはできますか? オブジェクト モデルと、これまでに把握できたことを以下に示します。

私の場合、OCRデータをシリアル化しています...これは単純化されたオブジェクトモデルです:

[ProtoContract(SkipConstructor = true, UseProtoMembersOnly = true)]
public class OcrTable
{
    [ProtoMember(1)]        
    public List<OcrTableCell> Cells;
}

[ProtoContract(SkipConstructor = true, UseProtoMembersOnly = true)]
public class OcrTableCell
{
    [ProtoMember(1)]
    public int Row;
    [ProtoMember(2)]
    public int Column;
    [ProtoMember(3)]
    public int RowSpan;

    //...

    [ProtoMember(10)]
    public int Height;

    [ProtoMember(11)]
    public List<OcrCharacter> Characters;
}

[ProtoContract(SkipConstructor = true, UseProtoMembersOnly = true)]
public class OcrCharacter
{
    [ProtoMember(1)]
    public int Code;
    [ProtoMember(2)]
    public int Data;
    [ProtoMember(3)]
    public int Confidence;

    //...

    [ProtoMember(11)]
    public int Width;
}

データは最終的に関連付けられたプリミティブ (ほとんどがint) の集まりにすぎないため、パック ビット シリアライゼーションの利点が役立つと思いますが、現在のクラス構造では、実際のリストはすべてカスタム型です。

パックされたビットのシリアライゼーションを可能にするために、カスタム型を完全に削除し、プリミティブの複数のリストをそれらのシーケンスによって関連付けることをいじくり回しました。例えば:

[ProtoContract(SkipConstructor = true, UseProtoMembersOnly = true)]
public class OcrTableCell
{
    [ProtoMember(1)]
    public int Row;

    //...

    [ProtoMember(10)]
    public int Height;

    [ProtoMember(11, IsPacked=true)]
    public List<int> CharacterCode;

    [ProtoMember(12, IsPacked=true)]
    public List<int> CharacterData;

    //...

    [ProtoMember(21, IsPacked=true)]
    public List<int> CharacterWidth;
}

List<OcrCharacter>の各フィールドに 1 つずつ、複数のリストに置き換えたことがわかりますOcrCharacter。これはシリアル化されたデータ サイズにかなり大きな影響を与え、場合によっては (gzip 後でも) 3 分の 2 減少します。

シリアライゼーションをサポートするためだけにオブジェクト モデルにこのような変更を加えるのは現実的ではないと思います...そして、シリアライゼーションの準備のために 2 番目の「ヘルパー」モデルを保持することは望ましくないようです。

それでも、データのオブジェクト モデルが原因で、シリアル化されたデータ サイズが人為的に膨らんでいることに悩まされています。

このタイプのオブジェクトグラフをシリアル化するためのシリアル化パラメータまたはライブラリのより良い選択はありますか? DataFormat=DataFormat.Groupリストに適用される属性を設定しようとしProtoMemberましたが、メッセージ サイズがまったく変化せず、混乱しました。

4

1 に答える 1

2

protobuf-net 内には、オブジェクト モデルを魔法のように再構成して特定の機能を利用するものは何もありません。これには、データの詳細な知識が必要です。これは、人間には明らかなことですが、一般化するのはかなり困難です。かなりの時間を費やすことなく、ここでの答えは単純です。モデルに配置されているとおりにシリアル化します。それが完璧なシナリオでない場合は、そうしてください。

役に立たないデータ形式については、Groupグループ化されたサブメッセージは次のようなものにのみ適用されますList<OcrCharacter>。フィールド番号が11であるため、2 バイトのオーバーヘッドが必要になることが保証されます。開始グループ マーカーに 1 バイト、終了グループ マーカーに 1 バイトです。代替手段は長さプレフィックスです。これには、フィールド ヘッダーに 1 バイトが必要で、サブメッセージの長さには可変varintバイト数が必要で、 としてエンコードされます。各サブメッセージが 128 バイト未満の場合でも、長さをエンコードするのに 1 バイトしか必要ありません (つまり、全体で 2 バイト)。これがおそらく違いがない理由です: 各個人OcrCharacterは十分に小さい (128 未満)バイト) それGroupは役に立ちません。

于 2013-06-07T22:52:15.793 に答える