2011-05-25 7 views
16

Actualmente estoy desarrollando una aplicación web y estoy usando JSON para solicitudes y respuestas ajax. Tengo un área donde devuelvo un conjunto de datos muy grande al cliente en forma de una matriz de más de 10000 objetos. Aquí es parte del ejemplo (la ha simplificado un poco):¿Cómo hago que mi JSON sea menos detallado?

"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" 
     } 
    ] 

Como, se puede imaginar, con un gran número de objetos en esta matriz, el tamaño de la Reponse JSON puede ser bastante grande.

Mi pregunta es, ¿hay un JSON stringifier/analizador que convertir la matriz "schedules" a ser algo como esto como una cadena JSON:

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

es decir, que no habría una serie al principio de la matriz "schedules" que contenía las claves de los objetos de esta matriz, y todas las demás matrices contenedoras contendrían los valores.

Podría, si quisiera, hacer la conversión en el servidor y analizarla en el cliente, pero me pregunto si hay una biblioteca estándar para analizar/encadenar JSON grande.

También podría ejecutarlo a través de un minificador, pero me gustaría conservar las claves que tengo actualmente ya que dan algún contexto dentro de la aplicación.

También espero que pueda criticar mi enfoque aquí o sugerir alternativas?

+2

Trate de usar la función gzip en su servidor o incluso intente gzip respuesta JSON por PHP (y enviarlo con un encabezado especial por supuesto). – silex

+1

Gracias, pero ya estoy usando gzip. –

+3

Mantendría el esquema y los datos separados (por ejemplo, '{schema :, data:}'), pero de lo contrario, creo que es válido. No estoy seguro de ninguna biblioteca existente para esto. Sin embargo, después de GZIP, ¿dará como resultado mega-ahorros? No estoy seguro, pero lo dudo parcialmente debido a la * buena duplicación de nombres clave * que existe. Burlarse de un caso de prueba (normal vs. normal + GZIP vs. hipotético-esquema vs. hipotético-esquema + GZIP) sería un buen primer paso para verificar los méritos potenciales de este enfoque. –

Respuesta

10

compresión HTTP (es decir, gzip o desinflar) ya hace exactamente eso. Los patrones repetidos, como las teclas JSON, se reemplazan con tokens, por lo que el patrón detallado solo tiene que ocurrir una vez por transmisión.

+0

He publicado algunas respuestas simuladas en mi "no respuesta". Un GZip del original ofrece la mejor * relación de compresión *. Sin embargo, el esquema + GZip es el * tamaño más pequeño *. Por lo tanto, GZip, al ser una compresión de propósito general y no un codificador especializado, * no puede * aprovechar al máximo la duplicación, aunque hace un trabajo bastante bueno. (El GZip del original es más pequeño que la versión de esquema porque también comprime todos los bits intermedios y el nombre "falso", etc.) –

+0

Eso es exactamente correcto, gracias ... Aunque tengo habilitado gzip, Esperaba bajar aún más ... Parece que tendré que tratar de optimizar mi solución de otras maneras. –

+2

Mientras considera otras optimizaciones, tenga en cuenta que su cuello de botella puede no estar en la transmisión. Incluso 10.000 registros como esos deben comprimir a menos de 200k por cable. Lo que sea que esté haciendo con ellos en el lado del cliente, utilizando JavaScript relativamente lento, es probable que sea mucho más lento que el tiempo de transmisión HTTP real (y agregar más complejidad a cómo el mensaje debe reconstituirse o usarse en JavaScript se agregará a carga del lado del cliente). –

6

He aquí un artículo que hace más o menos lo que estás buscando hacer:

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

A primera vista, parece que su ejemplo podría ser comprimido hasta el siguiente después del primer paso de la algoritmo, que realmente hará más trabajo en él en los siguientes pasos):

{ 
    "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" ] } 
    ] 
} 

Ya puede comenzar a ver las ventajas del algoritmo. Aquí está el resultado final después de la ejecución a través del compresor:

{ 
    "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"] } 
      ] 
     ] 
    } 
} 

Uno, obviamente, puede ver la mejora si tiene varios miles de registros. La salida aún es legible, pero creo que los otros chicos también tienen razón: un buen algoritmo de compresión va a eliminar los bloques de texto que se repiten de todos modos ...

+0

Es "* legible *" pero solo después de hacer un análisis de cabeza para calcular el * intento *. +1 de todos modos, para obtener información y vincular el esquema. –

+0

Gracias por el enlace, creo que estaba subestimando exactamente lo que Gzip podría hacer por mí. –

6

No es una respuesta, pero dar una estimación aproximada de "ahorros" basados ​​en entradas de 10k y algunos datos falsos :-) Esto es en respuesta a un comentario que publiqué. ¿La complejidad añadida hará que valga la pena el enfoque esquemático?

"Depende."

Este C# es LINQPad y está listo para someterse a las pruebas/modificación:

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)); 
} 

Mis resultados:

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 %

Conclusión:

  • el mayor ahorro es usar GZIP (mejor que simplemente usar schema'ize).
  • GZIP + schema'ized será el más pequeño en general.
  • Con GZIP hay sin punto para usar un minimizador de JavaScript normal (en este escenario).
  • Use GZIP (por ejemplo, DEFLATE); funciona muy bien en texto estructurado repetitivo (¡900% de compresión en condiciones normales!).

Happy coding.

+0

Gracias! ¡Aprecia los comentarios! –

0

Para el registro, lo estoy haciendo exactamente en php. Es una lista de objetos de una base de datos.

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

JSON: string (22501 longitud)

gz comprimido = cadena (711), pero es un formato binario.

gz comprimido + base64 = cadena (948) es un formato de texto.

Por lo tanto, es considerablemente más pequeño mediante el uso de una fracción de segundo.

Cuestiones relacionadas