2012-11-11 14 views
5

Sto tentando di caricare file CSV di grandi dimensioni (in genere 200-600mb) in modo efficiente con Java (meno memoria e il più rapido accesso possibile). Attualmente, il programma sta utilizzando un elenco di array di stringhe. Questa operazione è stata precedentemente gestita con un programma Lua utilizzando una tabella per ogni riga CSV e una tabella per contenere ciascuna tabella "riga".Java: come archiviare in modo efficiente una grande quantità di array di stringhe

Di seguito è riportato un esempio delle differenze di memoria e tempi di caricamento:

  • CSV file - 232mb
  • Lua - 549mb in memoria - 157 secondi per caricare
  • Java - 1,378mb in memoria - 12 secondi per caricare

Se ricordo correttamente, gli elementi duplicati in una tabella Lua esistono come riferimento al valore effettivo. Sospetto nell'esempio Java, l'elenco contiene copie separate di ogni valore duplicato e potrebbe essere correlato all'utilizzo della memoria più grande.

Di seguito alcuni retroscena sui dati all'interno dei file CSV:

  • Ogni campo è costituito da una stringa
  • campi specifici all'interno di ogni riga possono includere uno di un insieme di stringhe (campo Eg 3 potrebbe essere "rosso", "verde" o "blu").
  • Ci sono molte stringhe duplicate all'interno del contenuto.

seguito sono riportati alcuni esempi di ciò che può essere richiesto dei dati caricato:

  • una ricerca tra tutte le stringhe che tentano di abbinare con una determinata stringa e restituire le stringhe corrispondenti
  • Incontri visualizzare in una GUI tabella (ordinamento in grado tramite campi).
  • Modificare o sostituire stringhe.

La mia domanda: c'è una raccolta che richiede meno memoria per contenere i dati e offre ancora funzionalità per cercare/ordinare i dati in modo facile e veloce?

+1

se si sa che colonna 3 vale solo pochi valori possibili, si potrebbe [stagista loro] (http://docs.oracle .com/javase/7/docs/api/java/lang/String.html # intern% 28% 29) per ridurre l'utilizzo della memoria. Vedi anche: http://stackoverflow.com/a/1855195/829571 – assylias

+0

Grazie assylias eseguirò alcuni test usando quello. Sai se è efficace per le stringhe brevi - E.g. "A" o "Vai". La maggior parte dei campi contiene stringhe di 45 caratteri +, tuttavia alcuni sono piuttosto brevi (4 o meno). – user1816198

+2

Dai un'occhiata a http://stackoverflow.com/questions/12792942/alternatives-to-java-string-interning –

risposta

0

Forse questo articolo può essere di qualche aiuto:

http://www.javamex.com/tutorials/memory/string_saving_memory.shtml

+0

Grazie - informazioni molto utili. – user1816198

+1

Alla fine ho provato entrambi gli esempi presentati tramite l'articolo. Risulta che intern() risparmia più memoria. Continuerò a sperimentare (specialmente dopo aver terminato più del mio progetto) ma questo certamente mette l'uso della memoria in linea con Lua, anche se con tempi di caricamento molto più veloci. – user1816198

+0

Questo è il motivo per cui non dovresti fare solo risposte di collegamento - il link è ora morto. –

0

Per ottimizzare il tuo problema di memoria, consiglio di utilizzare lo schema Flyweight, specialmente per i campi con molti duplicati.

Come raccolta è possibile utilizzare uno TreeSet o TreeMap.

Se si dà una buona implementazione per la classe LineItem (implementare equals, hashcode e Comparable) è possibile ottimizzare la memoria, usare un sacco.

0

DAWG

A diretto aciclico grafico parola è il modo più efficace per memorizzare parole (migliore per il consumo di memoria comunque).

Ma probabilmente eccedere qui, come altri hanno detto di non creare duplicati, basta fare più riferimenti alla stessa istanza.

+0

Grazie esaminerò ancora questa opzione. Non considererei ancora eccessivo il problema: più efficiente è il numero di dati caricati per sessione e questo è più vantaggioso per l'utente finale. – user1816198

0

proprio come una nota a margine.

Per i dati di stringa duplicati di cui si dubita, non è necessario preoccuparsi di ciò, poiché a java interessano tutto ciò poiché tutte le stringhe sono definitive e tutti i riferimenti hanno come target lo stesso oggetto in memoria.

quindi non so come lua fa il lavoro, ma in Java dovrebbe essere anche abbastanza efficiente

+0

Ma se questo è vero di uguale a non è affatto necessario e == farà il lavoro per comparasion – Igor

+0

beh, equals è il modo corretto, come è il modo in cui devi confrontare gli oggetti in java, == potrebbe funzionare anche, ma è solo gentile di effetti collaterali, a causa del modo in cui JVM gestisce internamente le stringhe –

+0

Beh, non sono sicuro di quanta memoria java vm detenga internamente per mantenere i riferimenti alle stringhe, ma sono abbastanza sicuro che nel programma abbastanza grande == non funzionerà – Igor

1

Una soluzione facile. Puoi avere un po 'di HashMap dove metteresti i riferimenti a tutte le stringhe univoche. E in ArrayList si avrà solo il riferimento alle stringhe univoche esistenti in HashMap.

Qualcosa di simile:

private HashMap<String, String> hashMap = new HashMap<String, String>(); 

public String getUniqueString(String ns) { 
    String oldValue = hashMap.get(ns); 
    if (oldValue != null) { //I suppose there will be no null strings inside csv 
    return oldValue; 
    }   
    hashMap.put(ns, ns); 
    return ns; 
} 

utilizzo semplice:

List<String> s = Arrays.asList("Pera", "Zdera", "Pera", "Kobac", "Pera", "Zdera", "rus"); 
List<String> finS = new ArrayList<String>(); 
for (String er : s) { 
    String ns = a.getUniqueString(er); 
    finS.add(ns); 
} 
+0

il suono è come se steste cercando di ottimizzare le cose già ottimizzate da java (risparmiando memoria per le stringhe dupplicate in memoria), non c'è bisogno di una tale implementazione, vedere la mia risposta –

Problemi correlati