2017-02-24 6 views
1

Meine Funktion ist einfach nimmt eine CSV-Datei, die hochgeladen wurde und einige Formatierungsprobleme und eine andere Funktion aufrufen, um es zu bereinigen und seine Formatierung zu beheben.Ja OutOfMemoryError beim Mappen großer Liste von Tupeln

aber wenn ich meine Reinigungsfunktion mit einer Datei (als String) nennen, die sehr groß ist erhalte ich die Fehlermeldung:

[ERROR] [24/02/2017] [application-scheduler-1] [ActorSystem(application)] Uncaught error from thread [application-scheduler-1] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled java.lang.OutOfMemoryError: GC overhead limit exceeded

dies ist, wo sie versagt:

def clean(fileStr: String): String = { 

    val zippedWithIndex = fileStr.zipWithIndex 

    // i need to map it like this for the next stage of my cleaning 
    val indexCharMap = zippedWithIndex.map(cur => (cur._2,cur._1)).toMap 

    // my string builder 
    val builder = new StringBuilder() 


... 

} 

es nicht in die zippedWithIndex.map da die Datei sehr groß ist (die fileStr.length ist 10948026)

ich brauche es im iterating auf zippedWithIndex Ursache und ich muss die Fähigkeit zu haben Überprüfen Sie das Zeichen vor und nach (zum Beispiel: indexCharMap.get(chr._2 - 1))

es nur für wie eine Minute denken und dann löst die Ausnahme oben.

was wäre eine bessere Lösung?

Dank (außer Strömen bewegen, dass in der zweiten Version dieses Produkts wäre)!

So, jetzt funktioniert es wie folgt aus:

Ich brauche eine richtige CSV-Datei haben, das ist:

"Header1","Header2","Header3" 

"value1","value2","value3" 

aber die Datei, die im immer wird aus irgendeinem System bekommen, die ich nicht haben Zugang zu und die Formatierung ist gebrochen, was bedeutet, dass ich eine Datei wie diese bekommen:

"Header1","Header2","Header3" 

"val"ue1","val"ue2","val"ue"3" 

sein, weil die in den Werten im bekommen können Anführungszeichen und das System sein, dass sie nicht herausnimmt tun richtige Entkommen, die es so aussehen sollte:

"Header1","Header2","Header3" 

"val""ue1","val""ue2","val""ue""3" 

weil csv-Format in einer Art und Weise funktioniert, dass, wenn Sie ganz im Inneren Wert haben wollen Sie doppelte Anführungszeichen setzen müssen.

so es zu beheben im Iterieren durch zippedWithIndex und die Logik geht so:

zippedWithIndex.foreach(chr => { 

builder.append(chr._1) 

if(!currentlyInsideValue && begginingOfValue(indexCharMap.get(chr._2 - 1))) 
     currentlyInsideValue = true 

else if (currentlyInsideValue && endingValue(indexCharMap.get(chr._2 + 1))) 
     currentlyInsideValue = false 
     else 
     builder.append('"') 

} 
+0

Sie müssen uns über weitere Informationen sagen, was wollen Sie für 'indexCharMap' zu tun? – chengpohi

+0

@chengpohi Ich brauche es im iterating auf ZipPedWithIndex und ich muss die Fähigkeit haben, das Zeichen vor und nach zu überprüfen (zum Beispiel: 'indexCharMap.get (chr._2 - 1))' – JohnBigs

+0

val zippedWithIndex = fileStr.zipWithIndex? Wird dadurch nicht für jedes Zeichen in der Eingabezeichenfolge ein Index erstellt? Willst du das wirklich? Ah. Dein Kommentar oben deutet darauf hin, dass du es tust. Ok –

Antwort

0

Es sieht so aus, als müssten Sie nicht die gesamte Datei im Speicher halten, sondern nur jeweils eine Textzeile. Probieren Sie ein Programm wie das folgende aus.Schreiben Sie Ihren eigenen Code innerhalb von cleanOneLine zu fixieren, die Anführungszeichen innerhalb einer Textzeile

import scala.io.Codec 
import scala.io.Source 
import java.io.PrintWriter 

object CSVCleaner { 
    val fileName = "Broken.csv" 
    val output = "Fixed.csv" 

    def main(args: Array[String]) { 
    clean(fileName) 
    } 

    def clean(fileStr: String) { 
    val pw = new PrintWriter(output) 
    val source = Source.fromFile(fileName)(Codec.ISO8859) 
    source.getLines.foreach { line => 
     val clean = cleanOneLine(line) 
     pw.print(clean + "\n") 
    } 
    pw.flush 
    pw.close 
    source.close 
    } 

    def cleanOneLine(line: String): String = { 
    // your code here 
    "put, your, code, here" // ToDo 
    } 
} 
+0

ist eine gute Lösung, aber in meinem Fall ist der CSV wie ich sagte nicht in so gute Formatierung, und ich habe \ n in der Mitte eines Strings, und getLines gibt mir gebrochene Linien ... hast du eine andere Lösung, vielleicht eine, die ich noch den Prozess auf der ganzen Datei behalten kann ..? – JohnBigs

+0

Es klingt, als könnten Sie nicht garantieren (und mit "Sie" meine ich das Upstream-System), dass Wörter keine Anführungszeichen oder Zeilenumbrüche enthalten. Was können Sie garantieren? Wenn Sie garantieren könnten, dass "jede Zeile der CSV die gleiche N Anzahl von Spalten enthält und kein Feld Kommata enthält", könnten Sie die Datei vorverarbeiten, um (1) alle Zeilenumbrüche zu entfernen (2) die Datei erneut zu verarbeiten und zu trennen in Zeilen von N Spalten jeweils durch Zählen von Kommas (3) die Datei Zeile für Zeile verarbeiten und mit doppelten Anführungszeichen innerhalb von Feldern umgehen. Aber Sie müssen uns sagen, was über diese Datei garantiert werden kann. – radumanolescu

+0

Ohne irgendwelche Garantien, niemand kann feststellen, ob diese Eingabe enthält eine oder zwei Zeilen von Daten, vier oder drei Felder: "" a "," b ", \ n" c "," d "'. Wenn ein Feld doppelte Anführungszeichen, Kommas und Zeilenumbrüche enthalten kann, dann ist "b", \ n "c" ein Feld und die Eingabe enthält eine Datenzeile mit drei Feldern. Es könnte sogar eine Datenzeile mit einem Feld sein. Wir müssen wissen, was über die Daten garantiert ist, sonst hat das Problem möglicherweise keine Lösung. – radumanolescu

2

Anschlag toMap Funktion in zippedWithIndex.map(cur => (cur._2,cur._1)).toMap verwenden. Das ist der Grund für Ihre GC Overhead-Grenze überschritten Fehler. verarbeiten lazily die gesamte Datei zum Beispiel wie unten

val lines = for { 
    (line,index) <- Source.fromFile("output.txt").getLines.zipWithIndex 
} yield (line -> index) 

def cleaningFunction(currentLine: String, nextLine: String): String = { 
    //hypothetical cleaning function 
} 

val result = lines.toSeq zip lines.toSeq.tail // stream based sequence to access before/after lines 

result.map((x,y) => cleaningFunction(x,y)) 

Linien nun den gereinigten Inhalt der Datei hätte gezeigt, die später verwendet werden können.

+0

@chengpohi Ich habe die Antwort aktualisiert, um den fehlenden Teil zu enthalten .. –

Verwandte Themen