2011-12-05 31 views
1

我有一個奇怪的情況發生,我不太理解。Protobuf-net v2和大字典

我有一個'數據集'類,其中包含有關監視浮標的各種元數據,包括'傳感器'列表。

每個當前'sensorstate'。

每個'sensorstate'都有一些關於它的元數據(時間戳,更改原因等),但最重要的是它具有值的一個Dictionary<DateTime,float>

這些傳感器通常具有向上的50K數據點(年價值15分鐘數據讀數),所以我想以比默認的.NET BinaryFormatter等設立Protobuf-net將飛馳連載連載找到的東西,有點快快速。

不幸的是,我的問題發生在反序列化時,當我的值字典引發一個異常,因爲已經有一個項目添加了相同的密鑰,唯一的辦法就是啓用'OverwriteList',但我是一個很少有人不確定爲什麼當序列化時沒有任何重複鍵(它是一個字典),那麼爲什麼在我反序列化時有重複鍵?這也會引發數據完整性問題。

任何幫助解釋這將不勝感激。 (請注意,在給ProtoMember屬性id時,它們是否需要對類或整個項目是唯一的?我正在尋找與protobuf-net一起使用的無損壓縮建議作爲文件越來越相當大)

編輯:

我剛剛把我的源了GitHub上,這裏是有問題的類

SensorState(注:它目前擁有OverwriteList = TRUE,纔能有它爲其他開發工作)

下面是一個例子raw data file

使用SkipContructor標誌我已經試過,但即使它設置爲true它得到一個例外,除非OverwriteList也是值的字典真。

+0

喜;我已經在SensorState簡單的介紹一下,但它不是在「最小」的狀態下,其實我可以跳和複製任何東西(我嘗試添加越來越多的文件得到它來編譯,但沒有成功)。我在下面添加了一個*最小*示例(處理提供的數據),顯示沒有問題。你能通過提供一個最小*工作,可重現*的例子來幫助你,幫助你解決問題嗎? –

回答

1

這是我永遠表明它有道歉與我自己做的代碼無關。雖然我在這裏瘋狂的道具背後的protobuf和Marc Gravell隊爲protobuf網是非常地快。

發生了什麼事是在Sensor類我有一些邏輯,絕不讓一對夫婦的屬性不能爲空。

[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

很酷。 - 感謝您回來這個額外的信息。如果您遇到任何其他問題,請告訴我。 –

2

如果OverwriteList修復它,那麼它表明的詞典默認情況下有一些數據,也許通過構造函數或類似。如果確實來自構造函數,則可以使用[ProtoContract(SkipConstructor=true)]來禁用它。

如果我誤解了上述內容,如果可能的話,它可能有助於說明一個可重現的例子。

關於ID,它們只需要在每種類型中都是唯一的,並且建議保持它們很小(由於標籤的「varint」編碼,小鍵比「大鍵」便宜)。

如果您想真正縮小尺寸,我實際上建議您也查看數據的內容。例如,你說這是15分鐘的讀數......好了,我猜偶爾有差距,但你可以做,例如:

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

,並有Block爲15分鐘的值每連續一堆(這裏的假設是,以後每隔值爲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