2011-05-25 34 views
16

我目前正在開發一個Web應用程序並使用JSON來處理Ajax請求和響應。我有一個區域,我以超過10000個對象的數組的形式將一個非常大的數據集返回給客戶端。這裏的例子(其已經有所簡化)的一部分:如何讓我的JSON少冗長?

"schedules": [ 
     { 
      "codePractice": 35, 
      "codeScheduleObject": 576, 
      "codeScheduleObjectType": "", 
      "defaultCodeScheduleObject": 12, 
      "name": "Dr. 1" 
     }, 
     { 
      "codePractice": 35, 
      "codeScheduleObject": 169, 
      "codeScheduleObjectType": "", 
      "defaultCodeScheduleObject": 43, 
      "name": "Dr. 2" 
     }, 
     { 
      "codePractice": 35, 
      "codeScheduleObject": 959, 
      "codeScheduleObjectType": "", 
      "defaultCodeScheduleObject": 76, 
      "name": "Dr. 3" 
     } 
    ] 

如,你可以想像,有一個非常大的數字在這個數組中的對象,該JSON效應初探規模可能相當大。

我的問題是,是否有一個JSON stringifier /解析器將在"schedules"數組轉換成這個樣子的JSON字符串:

"schedules": [ 
    ["codePractice", "codeScheduleObject", "codeLogin", "codeScheduleObjectType", "defaultCodeScheduleObject","name"], 
    [35, 576, "", 12, "Dr. 1"], 
    [35, 169, "", 43, "Dr. 2"], 
    [35, 959, "", 76, "Dr. 3"], 
] 

即會有之初的數組該數組保存了該數組中對象的鍵,並且所有其他容器數組都將保存這些值。

我可以,如果我想,做服務器上的轉換並解析它在客戶端上,但我想知道是否有標準庫解析/字符串化大型JSON?

我也可以通過縮小器來運行它,但是我想保留當前的鍵,因爲它們在應用程序中給出了一些上下文。

我也希望你可以批評我的方法在這裏或建議的替代品?

+2

嘗試在您的服務器上使用gzip功能,甚至嘗試通過PHP對jz響應進行gzip壓縮(並將其與特殊頭文件一起發送)。 – silex 2011-05-25 21:24:47

+1

謝謝,但我已經在使用gzip。 – 2011-05-25 21:26:46

+3

我會保持模式和數據分離(例如'{schema :, data:}') - 但是否則我認爲它是有效的。我不確定任何現有的庫。但是,在GZIP之後,它會帶來巨大的節約嗎?我不確定,但部分懷疑它是因爲存在的重要名稱重複*。嘲笑一個測試案例(正常與正常+ GZIP與假設模式或假設模式+ GZIP)將是檢查這種方法的潛在優點的好的第一步。 – 2011-05-25 21:29:59

回答

10

HTTP壓縮(即gzip或deflate)已經正是這麼做的。重複模式(如JSON密鑰)被替換爲令牌,因此每個傳輸只需發生一次冗長模式。

+0

我在我的「不回答」中發佈了一些模擬答案。原始GZip提供最佳*壓縮比*。但是,模式+ GZip是*最小尺寸*。因此,GZip作爲一種通用的壓縮技術,而不是專門的編碼器,它不能充分利用複製功能,儘管它做得相當不錯。 (原始的GZip比模式版本更小,因爲它還壓縮所有的位間和「假」名稱等) – 2011-05-26 00:17:46

+0

這是完全正確的,謝謝...即使我已啓用gzip,我希望能夠把它降下來......看起來我必須嘗試以另一種方式優化我的解決方案。 – 2011-05-26 15:28:14

+2

在您考慮其他優化時,請記住您的瓶頸可能不在傳輸中。即使是這樣的10,000條記錄,也應該通過電纜壓縮到不到200k。無論你在客戶端用他們做什麼,使用相對較慢的JavaScript,都可能比實際的HTTP傳輸時間慢得多(並且增加了更復雜的消息必須在JavaScript中被重新構造或使用將增加到客戶端負擔)。 – 2011-05-26 16:06:00

6

這裏有一篇文章,確實相當多,你希望做什麼:

http://stevehanov.ca/blog/index.php?id=104

乍一看,它看起來像你的例子是壓縮成的第一步後,下面算法,這實際上將做更多的工作就可以在後續步驟):

{ 
    "templates": [ 
     ["codePractice", "codeScheduleObject", "codeScheduleObjectType", "defaultCodeScheduleObject", "name"] 
    ], 
    "values": [ 
     { "type": 1, "values": [ 35, 576, "", 12, "Dr. 1" ] }, 
     { "type": 1, "values": [ 35, 169, "", 43, "Dr. 2" ] }, 
     { "type": 1, "values": [ 35, 959, "", 76, "Dr. 3" ] } 
    ] 
} 

你可以開始看到該算法的好處了。這是通過壓縮機運行後的最終輸出:

{ 
    "f" : "cjson", 
    "t" : [ 
       [0,"schedules"], 
       [0,"codePractice","codeScheduleObject","codeScheduleObjectType","defaultCodeScheduleObject","name"] 
      ], 
    "v" : { 
     "" : [ 1, [ 
       { "" : [2, 35, 576, "", 12, "Dr. 1"] }, 
       { "" : [2, 35, 169, "", 43, "Dr. 2"] }, 
       { "" : [2, 35, 959, "", 76, "Dr. 3"] } 
      ] 
     ] 
    } 
} 

如果您有幾千條記錄,顯然可以看到改進。輸出仍然是可讀的,但我認爲其他人也是正確的:一個好的壓縮算法將刪除無論如何重複的文本塊...

+0

它是「*可讀*」,但只有在做一些頭解析來計算* intent *之後。 +1無論如何,爲信息和鏈接schema'izing。 – 2011-05-26 04:29:58

+0

感謝您的鏈接,我認爲我只是低估了Gzip可以爲我做什麼。 – 2011-05-26 15:28:56

6

不是一個答案,而是給出一個粗略的估計基於10k條目和一些虛假數據的「儲蓄」:-)這是對我發佈的評論的迴應。增加的複雜性會使模式化方法值得嗎?

「這要看。「

這個C#是LINQPad並準備到去化驗/修改:

string LongTemplate (int n1, int n2, int n3, string name) { 
    return string.Format(@" 
      {{ 
       ""codePractice"": {0}, 
       ""codeScheduleObject"": {1}, 
       ""codeScheduleObjectType"": """", 
       ""defaultCodeScheduleObject"": {2}, 
       ""name"": ""Dr. {3}"" 
      }}," + "\n", n1, n2, n3, name); 
} 

string ShortTemplate (int n1, int n2, int n3, string name) { 
    return string.Format("[{0}, {1}, \"\", {2}, \"Dr. {3}\"],\n", 
     n1, n2, n3, name); 
} 

string MinTemplate (int n1, int n2, int n3, string name) { 
    return string.Format("[{0},{1},\"\",{2},\"Dr. {3}\"],", 
     n1, n2, n3, name); 
} 

long GZippedSize (string s) { 
    var ms = new MemoryStream(); 
    using (var gzip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true)) 
    using (var sw = new StreamWriter(gzip)) { 
     sw.Write(s); 
    } 
    return ms.Position; 
} 

void Main() 
{ 
    var r = new Random(); 
    var l = new StringBuilder(); 
    var s = new StringBuilder(); 
    var m = new StringBuilder(); 
    for (int i = 0; i < 10000; i++) { 
     var n1 = r.Next(10000); 
     var n2 = r.Next(10000); 
     var n3 = r.Next(10000); 

     var name = "bogus" + r.Next(50); 
     l.Append(LongTemplate(n1, n2, n3, name)); 
     s.Append(ShortTemplate(n1, n2, n3, name)); 
     m.Append(MinTemplate(n1, n2, n3, name)); 
    } 

    var lc = GZippedSize(l.ToString()); 
    var sc = GZippedSize(s.ToString()); 
    var mc = GZippedSize(s.ToString()); 
    Console.WriteLine(string.Format("Long:\tNormal={0}\tGZip={1}\tCompressed={2:P}", l.Length, lc, (float)lc/l.Length)); 
    Console.WriteLine(string.Format("Short:\tNormal={0}\tGZip={1}\tCompressed={2:P}", s.Length, sc, (float)sc/s.Length)); 
    Console.WriteLine(string.Format("Min:\tNormal={0}\tGZip={1}\tCompressed={2:P}", m.Length, mc, (float)mc/m.Length)); 
    Console.WriteLine(string.Format("Short/Long\tRegular={0:P}\tGZip={1:P}", 
     (float)s.Length/l.Length, (float)sc/lc)); 
    Console.WriteLine(string.Format("Min/Long\tRegular={0:P}\tGZip={1:P}", 
     (float)m.Length/l.Length, (float)mc/lc)); 
} 

我的結果:

Long: Normal=1754614 GZip=197053 Compressed=11.23 % 
Short: Normal=384614 GZip=128252 Compressed=33.35 % 
Min: Normal=334614 GZip=128252 Compressed=38.33 % 
Short/Long Regular=21.92 % GZip=65.09 % 
Min/Long Regular=19.07 % GZip=65.09 %

結論:

  • 最大的單一儲蓄是使用GZIP(比使用schema'ize更好)。
  • GZIP + schema'ized將是最小的整體。
  • 使用GZIP有沒有點使用正常的JavaScript最小化(在這種情況下)。
  • 使用GZIP(例如DEFLATE);它對重複的結構化文本執行得非常好(正常情況下900%壓縮!)。

快樂編碼。

+0

謝謝!欣賞反饋! – 2011-05-26 15:29:25

0

爲了記錄,我正在做它完全在PHP。它是來自數據庫的對象列表。

$comp=base64_encode(gzcompress(json_encode($json))); 

JSON:字符串(22501長度)

GZ壓縮=串(711),但它的一個二進制格式。

gz compressed + base64 = string(948)其文本格式。

因此,通過使用秒的一小部分,其顯着更小。