2010-03-08 10 views
42

Ho alcuni file JSON con 500 MB. Se uso il json.load "banale" per caricare il suo contenuto tutto in una volta, consumerà molta memoria.Esiste una memoria efficiente e veloce per caricare file json di grandi dimensioni in python?

C'è un modo per leggere parzialmente il file? Se fosse un testo, file delimitato da linee, sarei in grado di scorrere le righe. Sto cercando l'analogia con esso.

Qualche suggerimento? Grazie

+0

Il problema che sto affrontando è che ho 195 file come quello da elaborare e sembra che il garbage collector di Python non stia facendo un buon lavoro. Dopo il decimo file, esaurisco la memoria. Sto usando Python 2.6.4 su Windows 7. Ho memoria RAM da 3 GB – duduklein

+1

Perché è necessario caricarli tutti in memoria in una volta? Sembra inefficace. –

+0

Se hai problemi con il caricamento di 500mb xml, vtd-xml è un modo per andare, la questione è se ha senso fare vtd-json ... –

risposta

-2

Risposta breve: no.

La corretta divisione di un file JSON richiederebbe una conoscenza approfondita del grafico dell'oggetto json per ottenere il risultato corretto.

Tuttavia, se si dispone di questa conoscenza, è possibile implementare un oggetto simile a un file che avvolge il file JSON e sputa i blocchi appropriati.

Ad esempio, se si sa che il file JSON è una singola matrice di oggetti, è possibile creare un generatore che avvolge il file JSON e restituisce blocchi della matrice.

Si dovrebbe eseguire un'analisi del contenuto di stringhe per ottenere il frammento del file JSON corretto.

Non so cosa generi il contenuto di JSON. Se possibile, prenderei in considerazione la possibilità di generare un numero di file gestibili, invece di un file enorme.

+0

Sfortunatamente, non posso pubblicare il file qui e non viene generato neanche da me. Stavo pensando di leggere il file JSON con il normale json.load e generare un nuovo testo, file delimitato da righe per scorrere su di esso. Il problema che sto affrontando è che ho 195 file come quello da elaborare e sembra che il garbage collector di Python non stia facendo un buon lavoro. Dopo il decimo file, esaurisco la memoria. Sto usando Python 2.6.4 su Windows 7. – duduklein

+0

Sarebbe bello se ci fosse un API JSON simile a SAX per Python. Come JACKSON per Java. –

+1

C'è ** jsonstreamer ** puoi [ottenerlo qui] (https://github.com/kashifrazzaqui/json-streamer) – kashif

3

Sulla tua menzione di esaurimento della memoria, devo chiedermi se stai effettivamente gestendo la memoria. Stai usando la parola chiave "del" per rimuovere il tuo vecchio oggetto prima di provare a leggerne uno nuovo? Python non dovrebbe mai conservare silenziosamente qualcosa in memoria se lo rimuovi.

+0

Non sto usando il comando del, dato che l'ho fatto automaticamente, perché lì non c'erano più riferimenti ad esso. – duduklein

+2

Poiché non è stato rimosso, hai ancora riferimenti. Le variabili globali sono il solito problema. –

1

oltre a @codeape

vorrei provare a scrivere un parser JSON personalizzato per aiutarti a capire la struttura del blob JSON si sta trattando. Stampa solo i nomi dei tasti, ecc. Crea un albero gerarchico e decidi tu stesso come si può. In questo modo puoi fare ciò che suggerisce @codeape - rompere il file in blocchi più piccoli, ecc.

11

Quindi il problema non è che ogni file sia troppo grande, ma che ce ne siano troppi e sembra che aggiungano in memoria. Il garbage collector di Python dovrebbe andare bene, a meno che tu non tenga traccia dei riferimenti che non ti servono. E 'difficile dire esattamente cosa sta succedendo senza altre informazioni, ma alcune cose si può provare:

  1. modulare: il vostro codice. Fare qualcosa di simile:

    for json_file in list_of_files: 
        process_file(json_file) 
    

    Se si scrive process_file() in modo tale che non si basa su alcun stato globale, e non si cambiamento qualsiasi stato globale, il garbage collector dovrebbe essere in grado di fare il suo lavoro .

  2. Gestire ciascun file in un processo separato. Invece di analizzare tutti i file JSON in una volta, scrivi un programma che ne analizzi solo uno e passali ciascuno da uno script di shell o da un altro processo python che chiama lo script tramite subprocess.Popen. Questo è un po 'meno elegante, ma se non funziona nient'altro, assicurerà che non si tratti di dati obsoleti da un file allo successivo.

Spero che questo aiuti.

2

Un'altra idea è provare a caricarlo in un database di archivio di documenti come MongoDB. Si occupa di grandi quantità di bit JSON. Sebbene si possa incontrare lo stesso problema nel caricare il JSON - evitare il problema caricando i file uno alla volta.

Se il percorso funziona per voi, allora si può interagire con i dati JSON attraverso il loro cliente e potenzialmente non devono contenere l'intero blob in memoria

http://www.mongodb.org/

2

"il garbage collector dovrebbe liberare la memoria"

Corretto.

Poiché non è così, qualcos'altro è sbagliato. Generalmente, il problema con la crescita infinita della memoria è rappresentato dalle variabili globali.

Rimuovere tutte le variabili globali.

Rende tutti i codici a livello di modulo in funzioni più piccole.

+0

Questo non sta aiutando, e fuori dall'argomento. –

48

C'era un duplicato a questa domanda che aveva una risposta migliore. Vedere https://stackoverflow.com/a/10382359/1623645, che suggerisce ijson.

Aggiornamento:

ho provato, e ijson è quello di JSON ciò SAX è quello di XML. Per esempio, si può fare questo:?

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

dove prefix è un indice separata da punti nella struttura di JSON (cosa succede se i vostri nomi chiave hanno punti in loro Credo che sarebbe un male per Javascript, anche. ..), theType descrive un evento simile a SAX, uno di 'null', 'boolean', 'number', 'string', 'map_key', 'start_map', 'end_map', 'start_array', 'end_array' e value è il valore dell'oggetto o None se the_type è un evento come l'inizio/fine di una mappa/matrice.

Il progetto ha alcune docstrings, ma non abbastanza documentazione globale. Ho dovuto scavare nello ijson/common.py per trovare quello che stavo cercando.

+8

Ho trovato questa non solo la migliore risposta alla domanda, ma l'introduzione più utile per IJSON che ho trovato dopo molti googling. Grazie per aver dedicato del tempo a passare attraverso la documentazione sparsa e presentare la sua base fuctionality in modo semplice e chiaro. – prooffreader

+2

Collegamento piacevole. Esiste un'altra funzionalità ijson: il generatore genera dizionari su un dato posto nei dati JSON. Confrontando il tempo di esecuzione con altre soluzioni, ijson è piuttosto lento (57 s rispetto a stdlib json), ma è eccellente se è necessario mantenere basso il consumo di memoria (13 MB rispetto a stdlib json 439 MB). Usando con backend yajl2, non era più veloce, ma il consumo di memoria è sceso a 5 MB. Testato su 3 file ciascuno di circa 30 MB di grandi dimensioni e con 300 mila record. –

6

Sì.

È possibile utilizzare jsonstreamer SAX-come parser spinta che ho scritto che vi permetterà di analizzare blocchi arbitrari di dimensioni, è possibile get it here e checkout il file README per gli esempi. È veloce perché usa la libreria "C" yajl.

Problemi correlati