2016-01-11 7 views
10

Ich bin neu in dem Projekt, und ich versuche, einen Connector zwischen Dataflow und einer Datenbank zu erstellen.Quelle Vs PTransform

Die Dokumentation besagt eindeutig, dass ich eine Quelle und eine Senke verwenden sollte, aber ich sehe eine Menge Leute, die direkt eine PTransform verwenden, die mit einem PInput oder einem PDone verbunden ist.

Die Source/Sink-API befindet sich in experimentell (was alle Beispiele mit der PTransform erklärt), scheint aber einfacher in einen benutzerdefinierten Runner zu integrieren (zB: funken).

Wenn ich auf den Code verweisen, werden die beiden Methoden verwendet. Ich sehe keinen Anwendungsfall, bei dem es interessanter wäre, die PTransform-API zu verwenden.

Soll die Source/Sink-API die PTranform-API ersetzen?

Habe ich etwas vermisst, dass die beiden Methoden deutlich unterscheiden?

Ist die Source/Sink-API stabil genug, um als die gute Möglichkeit zum Eingeben von Ein- und Ausgängen angesehen zu werden?

Vielen Dank für Ihren Rat!

+0

Große Frage! Wir schreiben jetzt eine gründliche Antwort. –

Antwort

12

Die Philosophie der Datenfluß ist, dass PTransform die Haupteinheit der Abstraktion und composability, das heißt, eine beliebige in sich geschlossene Datenverarbeitungsaufgabe als PTransform eingekapselt werden soll. Dies beinhaltet die Aufgabe, sich mit einem Speichersystem eines Drittanbieters zu verbinden: Daten von irgendwo aufzunehmen oder irgendwo zu exportieren.

Nehmen Sie zum Beispiel Google Cloud Datastore. Im Code-Schnipsel:

PCollection<Entity> entities = 
     p.apply(DatastoreIO.readFrom(dataset, query)); 
    ... 
    p.apply(some processing) 
    .apply(DatastoreIO.writeTo(dataset)); 

der Rückgabetyp von DatastoreIO.readFrom(dataset, query) ist eine Unterklasse von PTransform<PBegin, PCollection<Entity>>, und die Art der DatastoreIO.writeTo(dataset) ist eine Unterklasse von PTransform<PCollection<Entity>, PDone>.

Es ist wahr, dass diese Funktionen unter der Haube sind implementiert, um die Source und Sink Klassen verwenden, aber für einen Benutzer, der gerade etwas zu Datastor lesen will oder schreiben, das ist ein Detail Implementierung, dass in der Regel nicht (jedoch sollte Angelegenheit, Siehe den Hinweis am Ende dieser Antwort zum Aussetzen der Klasse Source oder Sink). Jeder Connector oder jede andere Datenverarbeitungsaufgabe ist ein PTransform.

Hinweis: Derzeit Anschlüsse, die von irgendwo gelesen neigen PTransform<PBegin, PCollection<T>> zu sein, und Anschlüsse, die dazu neigen, irgendwo schreiben PTransform<PCollection<T>, PDone> zu sein, aber wir erwägen Optionen zu erleichtern Anschlüsse in flexiblerer Weise zu nutzen (zum Beispiel Lesen von einem PCollection von Dateinamen).

Allerdings ist dieses Detail natürlich wichtig für jemanden, der einen neuen Stecker implementieren möchte. Insbesondere können Sie fragen:

Q: Warum brauche ich die Klassen Source und Sink überhaupt, wenn ich nur meinen Stecker als PTransform implementieren könnte?

A: Wenn Sie Ihren Anschluss von nur mithilfe der integrierten in-Transformationen (wie ParDo, implementieren können GroupByKey usw.), das ist eine absolut gültige Möglichkeit, einen Connector zu entwickeln. Die Klassen Source und Sink bieten jedoch einige Low-Level-Funktionen, die für den Fall, dass Sie sie benötigen, mühsam oder unmöglich wären, sich selbst zu entwickeln.

Zum Beispiel BoundedSource und UnboundedSource bieten Haken zu steuern, wie parallelisiert geschieht (sowohl Anfangs- und dynamische Arbeit Rebalancing - BoundedSource.splitIntoBundles, BoundedReader.splitAtFraction), während diese Haken sind momentan nicht für beliebige DoFn s ausgesetzt.

Sie technisch einen Parser für ein Dateiformat durch einen DoFn<FilePath, SomeRecord> zu schreiben, die den Dateinamen als Eingabe verwendet, liest die Datei und sendet SomeRecord implementieren könnte, aber diese DoFn würde Lese Teile der Datei auf mehrere Arbeiter nicht in der Lage sein, dynamisch parallelisieren falls die Datei zur Laufzeit sehr groß ist. Auf der anderen Seite, FileBasedSource hat diese Fähigkeit eingebaut, sowie die Handhabung von Glob-Filemustern und dergleichen.

Ebenso könnten Sie versuchen, einen Anschluss für ein Streaming-System implementieren, indem eine DoFn Implementierung, die ein Blindelement als Eingabe verwendet, stellt eine Verbindung her und Bäche alle Elemente in ProcessingContext.output(), aber DoFn s derzeit nicht unterstützt unbegrenzten Mengen des Schreibens Sie können auch die Checkpointing- und Deduplizierungsmaschinerie unterstützen, die für die starken Konsistenzgarantien benötigt wird, die Dataflow Streaming-Pipelines verleiht. UnboundedSource unterstützt das alles.

Sink (genauer gesagt, die Write.to()PTransform) ist auch interessant: es ist nur eine zusammengesetzte Transformation, die Sie selbst schreiben könnte, wenn man wollte (dh es hat keine hartcodierte Unterstützung in der Datenfluß-Läufer oder Backend), aber Es wurde unter Berücksichtigung typischer verteilter Fehlertoleranzprobleme entwickelt, die beim parallelen Schreiben von Daten in ein Speichersystem auftreten, und bietet Hooks, die Sie zwingen, diese Probleme zu berücksichtigen.: zB weil Datenbündel parallel geschrieben werden, und einige Bundles können für Fehlertoleranz wiederholt oder dupliziert werden, es gibt einen Haken zum "Festschreiben" nur der Ergebnisse der erfolgreich abgeschlossenen Bundles (WriteOperation.finalize).

Fassen wir zusammen: mit Source oder Sink APIs ein Verbinder hilft Ihnen in einer Weise strukturieren Sie den Code zu entwickeln, die in einem verteilten Verarbeitungs Einstellung funktionieren gut, und die Source-APIs geben Sie erweiterte Funktionen des Frameworks existieren. Aber wenn es sich bei Ihrem Connector um einen sehr einfachen Connector handelt, den Sie nicht benötigen, können Sie den Connector einfach aus anderen integrierten Transformationen zusammenstellen.

Frage: Angenommen, ich entscheide mich für die Verwendung von Source und Sink. Dann, wie verpacke ich meinen Verbinder als eine Bibliothek: sollte ich nur die Source oder Sink Klasse bereitstellen, oder sollte ich es in eine PTransform verpacken?

A: Ihr Anschluss schließlich als PTransform verpackt werden soll, so dass der Benutzer kann nur p.apply() es in ihrer Pipeline. Unter der Haube kann Ihre Transformation jedoch Klassen Source und Sink verwenden.

Ein übliches Muster ist die Source und Sink Klassen sowie zu belichten, die Verwendung des Fluent Builder Muster zu machen, und lassen sie der Benutzer in eine wickeln Read.from() oder Write.to() verwandeln sich, aber dies ist keine strenge Anforderung.

+0

"Connectors, die von irgendwo lesen, neigen zu sein" PTransform > '" - ist diese Information veraltet? In Beam 0.6.0 gibt es viel mehr 'PTransform >' als gibt es 'PTransform >' –

+0

Danke, habe ich meine Antwort behoben. – jkff