2012-04-30 6 views
20

Ich habe eine sehr große Textdateien (+ 10GB), die ich für einige Data Mining-Techniken lesen möchte. Um dies zu tun, verwende ich parallele Techniken mit MPI so viele Prozesse können auf die gleiche Datei zugreifen.
Tatsächlich möchte ich, dass jeder Prozess N Anzahl der Zeilen lesen. Da die Datei nicht strukturiert ist (die gleiche Anzahl von Feldern, aber jedes Feld kann unterschiedliche Anzahl von Zeichen enthalten), bin ich in der Pflicht, die Datei zu analysieren, und das ist nicht parallel und es braucht viel Zeit. Gibt es eine Möglichkeit, direkt auf eine bestimmte Anzahl von Zeilen zuzugreifen, um die Zeilen zu analysieren und zu zählen? Vielen Dank für Ihre Hilfe.Wie kann man direkt und effizient auf sehr große Textdateien zugreifen?

Antwort

21

Wenn Ihre Datei nicht anderweitig indiziert ist, gibt es keinen direkten Weg.

Indexierung könnte es wert sein (einmal scannen, um alle Zeilenenden zu finden und die Versätze jeder Zeile oder jeden Zeilenabschnitts zu speichern). Wenn Sie die Datei mehrere Male verarbeiten müssen und sich dies nicht ändert, können die Kosten für die Indizierung durch die einfache Verwendung des Index für weitere Durchläufe aufgewogen werden.

Andernfalls, wenn Sie nicht alle Jobs benötigen, genau die gleiche Anzahl von Zeilen/Elemente zu haben, könnten Sie es einfach täuschen.
Suchen Sie nach einem bestimmten Offset (sagen wir 1G) und suchen Sie nach dem nächsten Linientrennzeichen. Wiederholen Sie den Vorgang mit Offset 2G usw., bis Sie genügend Haltepunkte gefunden haben.

Sie können dann Ihre parallelen Aufgaben für jeden der identifizierten Chunks auslösen.

+0

Vielen Dank für Ihre Antwort. Ich denke, dass die zweite Idee besser ist, da ich die Datei normalerweise pünktlich analysiere. Wenn ich diese Lösung in Betracht ziehe, werde ich jedem Prozess Zugriff von einem bestimmten Offset verschaffen, sagen wir (Dateigröße/Prozessnummer * Prozess_Rank), dann suche ich nach dem Anfang einer neuen Zeile. Also würde ich bei schlechter number_of_process Linien verlieren? – ezzakrem

+0

+1 Einmaliges Suchen nach Zeilenumbrüchen und Übergabe der Indizes an andere Prozesse ist absolut vorzuziehen, da alle zufälligen Suchvorgänge mehrere Größenordnungen teurer sind als alles, was Sie durch Parallelisierung des Parsens einiger Felder pro Zeile kaufen können eine Textdatei Sequenzielles Lesen und Ziehen aus dem Puffer-Cache sind schnell, alles andere macht jede Optimierung zunichte. – Damon

+0

@ezzakrem: Wenn Sie es sich leisten können, bestimmte Zeilen nicht zu analysieren, könnten Sie das tun. Aber ich würde nicht. Bevor du mit dem Laichen von Arbeitern beginnst, findest du in deinem Hauptthread alle benötigten Breakpoints. Sie geben jedem Arbeiter Anfangs-/End-Offsets, bevor Sie ihn starten. – Mat

4

Nein, es gibt nicht: bis Sie Ihre unbekannten Daten nicht lesen, wird niemand wissen, wie viele neue Zeilenzeichen es gibt. Dieses Problem Komplexität ist O (n), was bedeutet, dass mindestens einmal müssen Sie die ganze Datei lesen. Dann sollten Sie eine Indextabelle erstellen, in der Sie aufzeichnen, wo sich neue Zeilenzeichen in Ihrer Datei befinden: Dies kann von allen Prozessen verwendet werden, und mit fseek können Sie den Zugriff drastisch beschleunigen.

+0

danke für die Antwort, es scheint eine gute Lösung. Ich werde das tun und sehen, ob es lohnt, da im seriellen Modus, ich lese die Datei, dann für jede Zeile ich viele CPU-Computing. Bisher habe ich zwei Lösungen: Ich parse Datei, um eine Indexdatei zu erstellen, dann können alle Prozesse es verwenden. Oder ich lasse einen Prozess aus der Datei lesen und mache andere Prozesse Berechnungen. – ezzakrem

+0

Mit O (n) bezog ich mich auf diese Notation: http://en.wikipedia.org/wiki/Time_complexity#Linear_time Übrigens ist die Indizierung sehr einfach paralel ausgeführt werden. Wenn Sie mehrere Prozesse haben, können Sie die Datei auch für die Indexierung aufteilen. Nehmen wir an, der 1. Prozess liest das 1. Gb, das 2. das 2. usw. durch und alle speichern die Positionen der neuen Zeilenzeichen in derselben gemeinsamen Ressource . Dies kann auch die Indizierung beschleunigen. Vergessen Sie jedoch nicht, dass das sequentielle Lesen je nach verwendeter Speicherhardware viel schneller ist. – MrTJ

+0

so ist es über Mischen von zwei Schritten 1- N-Prozesse bekommen Indizes, wie Sie gesagt haben. 2- für CPU-Computing, jeder Prozess direkt mit fseek() auf den spezifischen Offset zugreifen. Das sieht gut aus, um es zu versuchen. Danke – ezzakrem

10

Ein paar andere Optionen jenseits dessen, was hier erwähnt wurde, dass das Scannen die gesamte Datei nicht benötigen:

  1. einen Master-Prozess machen, die Leitungen über Leitungen/fifos an Kindprozesse schiebt, die die eigentliche Verarbeitung zu tun. Dies mag etwas langsamer sein, aber wenn 90% der Zeit, die in den Teilprozessen verbracht wird, das eigentliche Knirschen von Texten ist, sollte es in Ordnung sein.

  2. Ein blöder aber wirkungsvoller Trick: Sagen Sie, dass Sie N Prozesse haben, und Sie können jeden Prozess durch argv oder etwas sagen, dass es "Seriennummer" ist, z. processor -serial_number [1|2|3...N] -num_procs N können alle dieselben Daten lesen, aber nur Zeilen mit lineno % num_procs == serial_number verarbeiten. es ist ein bisschen weniger effizient, weil sie alle die gesamten Daten lesen werden, aber wieder, wenn sie nur auf jeder N-ten Zeile arbeiten, und das ist, was die meiste Zeit verbraucht, sollte es dir gut gehen.

+1

+1 für alternatives Denken. Manchmal ist der beste Weg zu gewinnen, die Regeln zu ändern. –

Verwandte Themen