2016-07-22 30 views
1

Ich benutze Spark 1.6.1 und ich versuche, einen Datenrahmen in ein Ork-Format zu speichern.Spark Datenrahmen SaveAsTable vs Speichern

Das Problem, mit dem ich konfrontiert bin, ist, dass die Speichermethode sehr langsam ist, und es dauert etwa 6 Minuten für 50M Orc-Datei auf jedem Executor. mit saveAsTable zu einem Bienenstock Tisch Dies ist, wie ich den Datenrahmen

dt.write.format("orc").mode("append").partitionBy("dt").save(path) 

Ich habe versucht, speichere die auch Ork Formate werden, und das scheint schneller zu sein etwa 20% bis 50% schneller, aber diese Methode hat ihre eigene Probleme - es scheint, dass wenn eine Aufgabe fehlschlägt, Versuche immer fehlschlagen, weil die Datei bereits existiert. Diese ist, wie ich den Datenrahmen speicherte

dt.write.format("orc").mode("append").partitionBy("dt").saveAsTable(tableName) 

Gibt es einen Grund Speichermethode so langsam ist? Mache ich etwas falsch?

+0

6 Minuten ist nicht so langsam für das Schreiben von 50M-Dateien. Klingt nach vielen Dateien! Wie groß ist jeder? Wie viele Testamentsvollstrecker? Wenn es eine Datei pro Zeile ist, dann ist das viel zu viel. Wenn sie für Ihr Speichersystem und die Anzahl der in einer typischen Abfrage verwendeten Knoten/Executoren geeignet sind, dann sind vielleicht 50M in Ordnung, aber ich bezweifle es. Wenn jede dieser 50M-Dateien 1G ist, dann sind das ~ 47 Petabyte, also bezweifle ich das. Wenn jedes 1MB ist, dann sind es 47 Terabyte, und ich würde vorschlagen, dass die Dateigröße zu klein ist, um die Tabelle effizient abzufragen. Was ist das Gesamtdatenvolumen? – Davos

+0

ist es tatsächlich 50 Mega-Datei. – user1960555

+1

wie, es ist nur eine 50MB Datei? Wenn es nur eine kleine Datei ist, dann ist es nicht sehr sinnvoll, sie zu partitionieren. Es ist möglich, dass Ihr dt-Feld viel zu viel Kardinalität hat und am Ende für jede Zeile Partitionen erstellt. Z.B. Wenn es ein Zeitstempel/Datum ist wie "2017-01-01 14:52:22", dann wird das Parittitoning für jede Sekunde passieren, die dann eine Ork-Datei für jede Partition schreiben würde. 50 MB könnte eine kleine Datei sein, aber es könnte viele Zeilen mit unterschiedlichen Zeitstempeln geben. z.B. Wenn jede Zeile ~ 8K ist, dann sind das ~ 6400 Zeilen, was eine Menge Datei-I/O ist. – Davos

Antwort

1

Das Problem liegt an der Methode partitionBy. PartitionBy liest die Werte der angegebenen Spalte und trennt dann die Daten für jeden Wert der Partitionsspalte. Versuchen Sie, es ohne Partition zu speichern, da wäre ein signifikanter Leistungsunterschied.

+0

Ich muss die Daten partitionieren, also ist dies keine Option. – user1960555

+0

Ich denke, das ist ein gültiger Punkt. Was ist dt? Ist das eine geeignete Spalte für die Partitionierung? Wenn die Kardinalität sehr hoch ist, ist es wahrscheinlich nicht angemessen. Wenn Sie beispielsweise einen Wert verwenden, der für jede Zeile des Datenrahmens unterschiedlich ist, werden zu viele Partitionen erstellt. Der Overhead all dieser Datei-I/O ist es nicht wert. – Davos

1

Siehe meine vorherigen Kommentare oben in Bezug auf Kardinalität und partitionBy.

Wenn Sie wirklich wollen, dass es partitionieren, und es ist nur eine 50 MB-Datei, dann etwas verwenden wie

dt.write.format("orc").mode("append").repartition(4).saveAsTable(tableName)

repartition wird 4 grob sogar Partitionen erstellen, anstatt, was Sie auf einem partitionieren tun dt-Spalte, die am Ende viele orc-Dateien schreiben könnte.

Die Auswahl von 4 Partitionen ist ein bisschen willkürlich. Sie werden nicht viel Leistung/Parallelisierung von der Partitionierung von kleinen Dateien wie das bekommen. Der Aufwand, mehr Dateien zu lesen, ist es nicht wert.