2011-12-05 3 views
1

私は、私がかなり理解していない奇妙な状況が起こっています。Protobuf-net v2と大きな辞書

私は 'センサー'のリストを含む監視ブイに関するさまざまなメタデータを保持する 'データセット'クラスを持っています。

それぞれ現在の「センサー状態」です。

各 'sensorstate'には、それに関するメタデータ(タイムスタンプ、変更の理由など)がありますが、最も重要なのはDictionary<DateTime,float>の値です。

これらのセンサは、一般的に50Kのデータポイント(15分データの読み取り値の価値がある年)の上向きに持っているので、私はデフォルトの.NET BinaryFormatterよりも直列化で少し速かった何かを探していましたので、幻想シリアライズされますProtobuf-netを設定速い。

残念なことに私の問題は、値の辞書が既に同じキーが追加されたアイテムが存在するため例外をスローするときにデシリアライズで発生し、デシリアライズするための唯一の方法は 'OverwriteList'を有効にすることですシリアル化しているときに重複するキーがない(それは辞書です)ので、逆シリアル化するとキーが重複するのはなぜですか?これはまた、データの完全性の問題を引き起こす。

これを説明する助けがあれば、非常に感謝します。

(ProtoMember属性IDを与えるときには、クラスやプロジェクト全体で一意である必要がありますか?また、protobuf-netと組み合わせて使用​​するロスレス圧縮の推奨事項を探しています

編集)かなり大きななっている:私はちょうどここにGitHubの上に私のソースを入れてきました

が問題のクラスである

SensorState(注:これは、現在持っているために、真のOverwriteList =を持っています他の開発のために働いています)

ここでは

raw data file

例である私はすでにSkipContructorフラグを使用してみましたが、それはOverwriteListは、値の辞書にも真でなければ、それは例外を取得し、trueに設定してもして。

+0

こんにちは。私はSensorStateについて簡単に見てきましたが、実際にジャンプして何かを再現できる最小限の状態ではありません(コンパイルするためにファイルを増やしてみましたが、成功しませんでした)。私は以下の* minimal *の例(提供されたデータの処理)を追加しました。問題はありません。この問題を示す最小限の実用的で再現性のある例を提供することで、私を助けてくれるでしょうか? –

答えて

1

私が今までそれが持っていた示唆をお詫び申し上げます場所です私のやり方ではないコードと関係があります。私はprotobufとMarc Gravellのチームにprotobuf-netのために怒っているが、真剣に速い。

Sensorクラスで何が起こっていたのですか。いくつかのプロパティが決してnullにならないようにするロジックがありました。

[ProtoMember(12)] 
public SensorState CurrentState 
{ 
    get { return (_currentState == null) ? RawData : _currentState; } 
    set { _currentState = value; } 
} 

Link

[ProtoMember(16)] 
public SensorState RawData 
{ 
    get { return _rawData ?? (_rawData = new SensorState(this, DateTime.Now, new Dictionary<DateTime, float>(), "", true, null)); } 
    private set { _rawData = value; } 
} 

Link

これは、私はそれがシリアル化プロセスを台無しにプロパティを使用していたときのために素晴らしく動作しますが。

シンプルな修正は、その代わりに、シリアライゼーションのために基礎となるオブジェクトをマークすることでした。

[ProtoMember(16)] 
private SensorState _rawData; 
[ProtoMember(12)] 
private SensorState _currentState; 

Link

+0

Cool。 - この余分な情報で戻ってきてくれてありがとう。あなたが他の問題を抱えたら教えてください。 –

2

OverwriteListがそれを修正した場合、には、おそらくコンストラクタなどを使用して辞書にデータがデフォルトで含まれていると私には示唆されています()。実際にコンストラクタから来ている場合は、[ProtoContract(SkipConstructor=true)]で無効にすることができます。

私が上記のことを誤解している場合は、可能であれば、再現可能な例で説明することをお勧めします。

IDについては、各タイプ内でユニークである必要があります(タグの「varint」エンコーディング、大きなキーよりも小さなキーが「安い」ため)。

実際にサイズを最小限に抑えたい場合は、実際にのコンテンツを見ることをお勧めします。たとえば、これは15分の読み値であると言います...まあ、私はそこに時折ギャップがありますが、あなたは、たとえば、行うことができます推測している:

Block (class) 
    Start Time (DateTime) 
    Values (float[]) 

と15分値のすべての連続した束のためBlockを持っている(ここでの仮定は、すべての値が15の後であるということです最後に、新しいブロックが開始されます)。したがって、単一の辞書の代わりに複数のBlockインスタンスを格納しています。これは利点があります:

  • あなたはそれがすべての中間のタグを追加する必要はありませんを意味し、山車のエンコーディング「パック」を使用することができます
  • を格納するためにはるかに少ないDateTime値を、あなたに配列/リスト([ProtoMember({key}, IsPacked = true)])をマークすることによって、これを行う - それは唯一のいくつかの基本的なデータ型(いないサブオブジェクト)

組み合わせて、これらの二つの微調整が生じる可能性が大幅に節約

に動作することを指摘します

データに文字列が多い場合は、GZIP/DEFLATEを試すことができます。もちろんでもこれらの方法を試すことができますが、大量の文字列データを使用しないと、あまり圧縮を余儀なくされることに慎重になります。供給(CSV)データファイルに基づいて更新として


、ここで辞書を扱うは固有の問題がありません - 示すように:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using ProtoBuf; 
class Program 
{ 
    static void Main() 
    { 
     var data = new Data 
     { 
      Points = 
      { 
       {new DateTime(2009,09,1,0,0,0), 11.04F}, 
       {new DateTime(2009,09,1,0,15,0), 11.04F}, 
       {new DateTime(2009,09,1,0,30,0), 11.01F}, 
       {new DateTime(2009,09,1,0,45,0), 11.01F}, 
       {new DateTime(2009,09,1,1,0,0), 11F}, 
       {new DateTime(2009,09,1,1,15,0), 10.98F}, 
       {new DateTime(2009,09,1,1,30,0), 10.98F}, 
       {new DateTime(2009,09,1,1,45,0), 10.92F}, 
       {new DateTime(2009,09,1,2,00,0), 10.09F}, 
      } 
     }; 

     var ms = new MemoryStream(); 
     Serializer.Serialize(ms, data); 
     ms.Position = 0; 
     var clone =Serializer.Deserialize<Data>(ms); 
     Console.WriteLine("{0} points:", clone.Points.Count); 
     foreach(var pair in clone.Points.OrderBy(x => x.Key)) 
     { 
      float orig; 
      data.Points.TryGetValue(pair.Key, out orig); 
      Console.WriteLine("{0}: {1}", pair.Key, pair.Value == orig ? "correct" : "FAIL"); 
     } 
    } 
} 
[ProtoContract] 
class Data 
{ 
    private readonly Dictionary<DateTime, float> points = new Dictionary<DateTime, float>(); 
    [ProtoMember(1)] 
    public Dictionary<DateTime, float> Points { get { return points; } } 
} 
+0

私はすでに[ProtoContract(SkipConstructor = true)]を設定していますが、問題はまだ残っています。私はソースにリンクして生データファイルを提供するために投稿を更新しました。 – Technicolour

+0

私の問題は完全に私自身のものでした。それ以外の点についてはごめんなさい。 – Technicolour

関連する問題