python - not - ¿Cuál es la mejor forma de comprimir json para almacenar en una tienda basada en memoria como redis o memcache?
redis set json object node (4)
Requisito: objetos Python con 2-3 niveles de anidación que contienen datypes básicos como enteros, cadenas, listas y dicts. (sin fechas, etc.), necesita ser almacenado como json en redis contra una clave. ¿Cuáles son los mejores métodos disponibles para comprimir json como una cadena de baja huella de memoria. Los objetos de destino no son muy grandes, tienen 1000 elementos pequeños en promedio, o alrededor de 15000 caracteres cuando se convierten a JSON.
p.ej.
>>> my_dict
{''details'': {''1'': {''age'': 13, ''name'': ''dhruv''}, ''2'': {''age'': 15, ''name'': ''Matt''}}, ''members'': [''1'', ''2'']}
>>> json.dumps(my_dict)
''{"details": {"1": {"age": 13, "name": "dhruv"}, "2": {"age": 15, "name": "Matt"}}, "members": ["1", "2"]}''
### SOME BASIC COMPACTION ###
>>> json.dumps(my_dict, separators=('','','':''))
''{"details":{"1":{"age":13,"name":"dhruv"},"2":{"age":15,"name":"Matt"}},"members":["1","2"]}''
1 / ¿Hay alguna otra forma mejor de comprimir json para guardar la memoria en redis (también asegurando una descodificación ligera después).
2 / ¿Qué tan bueno sería un candidato msgpack [http://msgpack.org/]?
3 / ¿Debería considerar opciones como pickle también?
Otra posibilidad sería usar el formato de almacenamiento de MongoDB, BSON .
Puede encontrar dos implementaciones de python en la página de implementación en ese sitio.
editar: ¿por qué no solo guardar el diccionario y convertir a json en la recuperación?
Solo usamos gzip
como compresor.
import gzip
import cStringIO
def decompressStringToFile(value, outputFile):
"""
decompress the given string value (which must be valid compressed gzip
data) and write the result in the given open file.
"""
stream = cStringIO.StringIO(value)
decompressor = gzip.GzipFile(fileobj=stream, mode=''r'')
while True: # until EOF
chunk = decompressor.read(8192)
if not chunk:
decompressor.close()
outputFile.close()
return
outputFile.write(chunk)
def compressFileToString(inputFile):
"""
read the given open file, compress the data and return it as string.
"""
stream = cStringIO.StringIO()
compressor = gzip.GzipFile(fileobj=stream, mode=''w'')
while True: # until EOF
chunk = inputFile.read(8192)
if not chunk: # EOF?
compressor.close()
return stream.getvalue()
compressor.write(chunk)
En nuestro caso de uso almacenamos el resultado como archivos, como se puede imaginar. Para usar cadenas solo en la memoria, puede usar un objeto cStringIO.StringIO()
como un reemplazo para el archivo también.
Una forma fácil de "postprocesamiento" es crear un mapa de "nombre de clave corta" y ejecutar el json generado a través de eso antes del almacenamiento, y de nuevo (invertir) antes de deserializar a un objeto. Por ejemplo:
Before: {"details":{"1":{"age":13,"name":"dhruv"},"2":{"age":15,"name":"Matt"}},"members":["1","2"]}
Map: details:d, age:a, name:n, members:m
Result: {"d":{"1":{"a":13,"n":"dhruv"},"2":{"a":15,"n":"Matt"}},"m":["1","2"]}
Simplemente vaya a través de la json y reemplace key-> value en el camino a la base de datos, y value-> key de camino a la aplicación.
También puede gzip para bondad extra (sin embargo, no será una cadena después de eso).
Si quieres que sea rápido, prueba lz4 . Si quieres que se comprima mejor, ve por lzma .
¿Hay alguna otra forma mejor de comprimir json para guardar la memoria en redis (también asegurando una decodificación ligera después)?
¿Qué tan bueno sería un candidato msgpack [ http://msgpack.org/] ?
Msgpack es relativamente rápido y tiene una huella de memoria más pequeña. Pero ujson es generalmente más rápido para mí. Debe compararlos en sus datos, medir las tasas de compresión y descompresión y la relación de compresión.
¿Consideraré opciones como pickle también?
Considere tanto pickle (cPickle in partucular) como Marshal. Ellos son rápidos. Pero recuerda que no son seguros ni escalables, y pagas la velocidad con la responsabilidad adicional.