web-dev-qa-db-fra.com

Existe-t-il un moyen efficace et rapide de mémoire pour charger de gros fichiers json en python?

J'ai quelques fichiers json avec 500 Mo. Si j'utilise le fichier "trivial" json.load pour charger son contenu en une seule fois, il consommera beaucoup de mémoire.

Existe-t-il un moyen de lire partiellement le fichier? S'il s'agissait d'un fichier texte, délimité par des lignes, je pourrais parcourir les lignes. Je cherche l'analogie avec cela.

Aucune suggestion? Merci

56
duduklein

Il y avait un double à cette question qui avait une meilleure réponse. Voir https://stackoverflow.com/a/10382359/1623645 , ce qui suggère ijson .

Mise à jour:

Je l'ai essayé et ijson est pour JSON ce que SAX est pour XML. Par exemple, vous pouvez faire ceci:

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

prefix est un index séparé par des points dans l'arborescence JSON (que se passe-t-il si vos noms de clés contiennent des points? Je suppose que ce serait également mauvais pour Javascript ...), theType décrit un événement de type SAX, l'un des 'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array' et value est la valeur de l'objet ou None si the_type est un événement comme démarrer/terminer une carte/un tableau.

Le projet a quelques docstrings, mais pas assez de documentation globale. J'ai dû creuser dans ijson/common.py pour trouver ce que je cherchais.

71
Jim Pivarski

Le problème n'est donc pas que chaque fichier est trop volumineux, mais qu'il y en a trop et qu'ils semblent s'additionner en mémoire. Le garbage collector de Python devrait être correct, à moins que vous ne conserviez des références dont vous n'avez pas besoin. Il est difficile de dire exactement ce qui se passe sans plus d'informations, mais vous pouvez essayer certaines choses:

  1. Modularisez votre code. Faites quelque chose comme:

    for json_file in list_of_files:
        process_file(json_file)
    

    Si vous écrivez process_file() de telle manière qu'il ne repose sur aucun état global et ne change aucun état global, le garbage collector devrait être en mesure de faire son travail.

  2. Traitez chaque fichier dans un processus distinct. Au lieu d'analyser tous les fichiers JSON à la fois, écrivez un programme qui n'en analyse qu'un seul et transmettez-les chacun à partir d'un script Shell ou d'un autre processus python qui appelle votre script via subprocess.Popen. C'est un peu moins élégant, mais si rien d'autre ne fonctionne, cela vous assurera de ne pas conserver les données périmées d'un fichier à l'autre.

J'espère que cela t'aides.

14
jcdyer

Oui.

Vous pouvez utiliser jsonstreamer analyseur Push de type SAX que j'ai écrit qui vous permettra d'analyser des morceaux de taille arbitraire, vous pouvez l'obtenir ici et consultez le README pour des exemples. C'est rapide car il utilise la bibliothèque yajl 'C').

8
kashif

En ce qui concerne votre manque de mémoire, je dois vous demander si vous gérez réellement la mémoire. Utilisez-vous le mot-clé "del" pour supprimer votre ancien objet avant d'essayer d'en lire un nouveau? Python ne devrait jamais conserver silencieusement quelque chose en mémoire si vous le supprimez.

3
Aea

"le garbage collector devrait libérer la mémoire"

Correct.

Comme ce n'est pas le cas, quelque chose d'autre ne va pas. Généralement, le problème de la croissance de mémoire infinie est lié aux variables globales.

Supprimez toutes les variables globales.

Transformez tout le code au niveau du module en fonctions plus petites.

3
S.Lott

Une autre idée est d'essayer de le charger dans une base de données de stockage de documents comme MongoDB. Il traite bien les gros blobs de JSON. Bien que vous puissiez rencontrer le même problème lors du chargement du JSON, évitez le problème en chargeant les fichiers un par un.

Si le chemin fonctionne pour vous, vous pouvez alors interagir avec les données JSON via leur client et ne pas avoir à conserver l'intégralité du blob en mémoire

http://www.mongodb.org/

2
George Godik

en plus de @codeape

J'essaierais d'écrire un analyseur json personnalisé pour vous aider à comprendre la structure du blob JSON que vous traitez. N'imprimez que les noms des clés, etc. Créez un arbre hiérarchique et décidez (vous-même) comment vous pouvez le découper. De cette façon, vous pouvez faire ce que suggère @codeape - diviser le fichier en petits morceaux, etc.

1
George Godik