2010-03-08 10 views
42

Tengo algunos archivos json con 500MB. Si uso el json.load "trivial" para cargar todo su contenido de una vez, consumirá mucha memoria.¿Existe una manera eficiente y rápida de cargar archivos grandes json en python?

¿Hay alguna manera de leer parcialmente el archivo? Si fuera un archivo de texto delimitado por líneas, podría iterar sobre las líneas. Estoy buscando una analogía para eso.

¿Alguna sugerencia? Gracias

+0

El problema que estoy enfrentando es que tengo 195 archivos para procesar y parece que el recolector de basura de Python no está haciendo un buen trabajo. Después del 10mo archivo, me quedo sin memoria. Estoy usando Python 2.6.4 en Windows 7. Tengo memoria RAM de 3GB – duduklein

+1

¿Por qué necesitas cargar todos ellos en la memoria a la vez? Eso parece ineficaz. –

+0

Si tiene problemas para cargar 500mb xml, vtd-xml es una manera de hacerlo, la cuestión es si tiene sentido hacer vtd-json ... –

Respuesta

-2

Respuesta corta: no.

La división correcta de un archivo json requeriría un conocimiento profundo del gráfico del objeto json para hacerlo bien.

Sin embargo, si tiene este conocimiento, entonces podría implementar un objeto similar a un archivo que envuelva el archivo json y escuche los fragmentos adecuados.

Por ejemplo, si sabe que su archivo json es una única matriz de objetos, puede crear un generador que envuelva el archivo json y devuelva los fragmentos de la matriz.

Tendría que hacer un cierto análisis de contenido de cadena para obtener la fragmentación correcta del archivo json.

No sé qué genera su contenido json. Si es posible, consideraría generar una cantidad de archivos manejables, en lugar de un solo archivo enorme.

+0

Desafortunadamente, no puedo publicar el archivo aquí y tampoco lo he generado. Estaba pensando en leer el archivo json con el json.load regular y generar un nuevo texto, un archivo delimitado por líneas para iterar sobre él. El problema al que me enfrento es que tengo que procesar 195 archivos como este y parece que el recolector de basura de Python no está haciendo un buen trabajo. Después del 10mo archivo, me quedo sin memoria. Estoy usando Python 2.6.4 en Windows 7. – duduklein

+0

Sería genial si hubiera una API JSON apta para Python. Como JACKSON para Java. –

+1

Hay ** jsonstreamer ** puede [obtenerlo aquí] (https://github.com/kashifrazzaqui/json-streamer) – kashif

3

En su mención de que se está quedando sin memoria, debo preguntar si realmente está administrando la memoria. ¿Estás usando la palabra clave "del" para eliminar tu objeto anterior antes de intentar leer uno nuevo? Python nunca debe retener silenciosamente algo en la memoria si lo elimina.

+0

No estoy usando el comando del, ya que si lo hacía automáticamente, porque allí no hubo más referencias a eso. – duduklein

+2

Como no se eliminó, usted todavía tiene referencias. Las variables globales son el problema habitual. –

1

además de @codeape

Me gustaría tratar de escribir un analizador JSON personalizado para ayudar a determinar la estructura de la burbuja JSON se está tratando. Imprima solo los nombres de las teclas, etc. Haga un árbol jerárquico y decida (usted mismo) cómo puede dividirlo. De esta manera usted puede hacer lo que sugiere @codeape - romper el archivo en trozos más pequeños, etc

11

Así que el problema no es que cada archivo es demasiado grande, pero que hay demasiados de ellos, y ellos parecen estar añadiendo arriba en la memoria. El recolector de basura de Python debería estar bien, a menos que guardes las referencias que no necesitas. Es difícil saber exactamente qué está sucediendo sin más información, pero hay algunas cosas que puede probar:

  1. Modifique su código. Hacer algo como:

    for json_file in list_of_files: 
        process_file(json_file) 
    

    Si se escribe process_file() de tal manera que no se basa en ningún estado global, y no cambio de cualquier estado global, el recolector de basura debe ser capaz de hacer su trabajo .

  2. Trate con cada archivo en un proceso separado. En lugar de analizar todos los archivos JSON a la vez, escriba un programa que analiza solo uno, y pase cada uno desde un script de shell, o desde otro proceso de python que llame a su script a través del subprocess.Popen. Esto es un poco menos elegante, pero si nada más funciona, se asegurará de que no se mantenga a datos obsoletos de un archivo al siguiente.

Espero que esto ayude.

2

Otra idea es intentar cargarla en una base de datos de almacenamiento de documentos como MongoDB. Se trata de grandes manchas de JSON también. Aunque podría encontrarse con el mismo problema al cargar JSON, evite el problema cargando los archivos de uno en uno.

Si la ruta funciona para usted, entonces usted puede interactuar con los datos JSON a través de su cliente y, potencialmente, no tiene que contener todo el blob en la memoria

http://www.mongodb.org/

2

"el recolector de basura debe liberar la memoria"

Correcto.

Como no es así, algo más está mal. En general, el problema con el crecimiento de la memoria infinita son las variables globales.

Eliminar todas las variables globales.

Convierta todos los códigos de nivel de módulo en funciones más pequeñas.

+0

Esto no está ayudando, y fuera del tema. –

48

Hubo un duplicado de esta pregunta que tenía una mejor respuesta. Consulte https://stackoverflow.com/a/10382359/1623645, que sugiere ijson.

Actualización:

lo probé, y es ijson a JSON lo SAX es a XML. Por ejemplo, usted puede hacer esto:?

import ijson 
for prefix, the_type, value in ijson.parse(open(json_file_name)): 
    print prefix, the_type, value 

donde prefix es un índice separados por puntos en el árbol de JSON (lo que sucede si los nombres de claves tienen punto en ellos supongo que sería malo para Javascript, también. ..), theType describe un evento tipo SAX, uno de 'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array', y value es el valor del objeto o None si the_type es un evento como iniciar/finalizar un mapa/matriz.

El proyecto tiene algunas docstrings, pero no suficiente documentación global. Tuve que buscar en ijson/common.py para encontrar lo que estaba buscando.

+8

Encontré esta no solo la mejor respuesta a la pregunta, pero la introducción más útil a ijson que pude encontrar después de mucho googlear. Gracias por tomarse el tiempo para revisar la escasa documentación y presentar su funcionalidad básica de forma tan simple y clara. – prooffreader

+2

Buen enlace. Hay otra característica de ijson: generador de generadores de diccionarios en un lugar determinado en datos JSON. Al comparar el tiempo de ejecución con otras soluciones, ijson es bastante lento (57 s frente a stdlib json), pero es excelente si necesita mantener bajo el consumo de memoria (13 MB frente a stdlib json 439 MB). Al usar con el backend yajl2, no fue más rápido, pero el consumo de memoria bajó a 5 MB. Probado en 3 archivos, cada uno de aproximadamente 30 MB de ancho y con 300 mil registros. –

6

Sí.

Puede utilizar jsonstreamer SAX-como empuje analizador que he escrito, que le permitirá analizar sintácticamente trozos del tamaño arbitrarios, puede get it here, y obtenga el README para ejemplos. Es rápido porque usa la biblioteca 'C' yajl.

Cuestiones relacionadas