Источник против PTransform

Я новичок в этом проекте и пытаюсь создать соединитель между потоком данных и базой данных.

В документации четко указано, что я должен использовать Source и Sink, но я вижу, что многие люди напрямую используют PTransform, связанный с PInput или PDone.

API источника / приемника находится в экспериментальном состоянии (что объясняет все примеры с PTransform), но кажется более легким интегрировать его с пользовательским исполнителем (например, Spark).

Если я обращаюсь к коду, используются два метода. Я не вижу ни одного варианта использования, где было бы более интересно использовать PTransform API.

Должен ли API Source / Sink заменить API PTranform?

Я пропустил что-то, что четко различает эти два метода?

Достаточно ли стабилен Source / Sink API, чтобы его можно было считать хорошим способом кодирования входных и выходных данных?

Спасибо за совет!


person pibafe    schedule 11.01.2016    source источник
comment
Отличный вопрос! Сейчас мы пишем исчерпывающий ответ.   -  person Sam McVeety    schedule 11.01.2016


Ответы (1)


Философия Dataflow заключается в том, что PTransform является основной единицей абстракции и компоновки, т.е. любая автономная задача обработки данных должна быть инкапсулирована как PTransform. Сюда входит задача подключения к сторонней системе хранения: получение данных откуда-то или их экспорт куда-то.

Возьмем, к примеру, Google Cloud Datastore. Во фрагменте кода:

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

тип возвращаемого значения DatastoreIO.readFrom(dataset, query) является подклассом PTransform<PBegin, PCollection<Entity>>, а тип DatastoreIO.writeTo(dataset) является подклассом PTransform<PCollection<Entity>, PDone>.

Верно, что эти функции реализуются под капотом с использованием классов Source и Sink, но для пользователя, который просто хочет прочитать или записать что-то в Datastore, это деталь реализации, которая обычно не имеет значения (однако см. обратите внимание в конце этого ответа о раскрытии класса Source или Sink). Любой коннектор или любая другая задача обработки данных - это PTransform.

Примечание. В настоящее время коннекторы, которые читают откуда-то, обычно PTransform<PBegin, PCollection<T>>, а коннекторы, которые пишут куда-то, как правило, PTransform<PCollection<T>, PDone>, но мы рассматриваем варианты, которые упростят использование коннекторов более гибкими способами (например, чтение из PCollection имен файлов).

Однако, конечно, эта деталь важна для тех, кто хочет реализовать новый соединитель. В частности, вы можете спросить:

В: Зачем мне вообще нужны классы Source и Sink, если я могу просто реализовать свой коннектор как PTransform?

О: Если вы можете реализовать свой коннектор, просто используя встроенные преобразования (например, ParDo, GroupByKey и т. д.), это вполне допустимый способ разработки коннектора. Однако классы Source и Sink предоставить некоторые низкоуровневые возможности, которые в случае необходимости были бы громоздкими или невозможными для самостоятельной разработки.

Например, BoundedSource и UnboundedSource предоставляют хуки для управления тем, как происходит распараллеливание (как начальная, так и динамическая перебалансировка работы - BoundedSource.splitIntoBundles, BoundedReader.splitAtFraction), в то время как эти хуки в настоящее время не доступны для произвольных DoFns.

Вы можете технически реализовать синтаксический анализатор для формата файла, написав DoFn<FilePath, SomeRecord>, который принимает имя файла в качестве входных, читает файл и выдает SomeRecord, но этот DoFn не сможет динамически распараллелить чтение частей файла на нескольких рабочих, если файл оказался очень большим во время выполнения. С другой стороны, FileBasedSource имеет встроенную возможность, а также обработку шаблонов файлов glob и тому подобного.

Точно так же вы можете попробовать реализовать соединитель для потоковой системы, реализовав DoFn, который принимает фиктивный элемент в качестве входных данных, устанавливает соединение и передает все элементы в ProcessingContext.output(), но DoFns в настоящее время не поддерживают запись неограниченного количества выходных данных из одного пакета. , а также они явно не поддерживают механизм контрольных точек и дедупликации, необходимый для обеспечения строгой согласованности, которую Dataflow предоставляет потоковым конвейерам. UnboundedSource, напротив, все это поддерживает.

Sink (точнее, Write.to() PTransform) также интересен: это просто составное преобразование, которое вы могли бы написать самостоятельно, если захотите (т.е. оно не имеет жестко запрограммированной поддержки в средстве выполнения или бэкэнде потока данных), но оно было разработано с помощью рассмотрение типичных проблем распределенной отказоустойчивости, которые возникают при параллельной записи данных в систему хранения, и предоставляет ловушки, которые заставляют вас помнить об этих проблемах: например, потому что пакеты данных записываются параллельно , и некоторые пакеты могут быть повторены или дублированы для обеспечения отказоустойчивости, есть ловушка для «фиксации» только результатов успешно завершенных пакетов (WriteOperation.finalize).

Подводя итог: использование Source или Sink API для разработки коннектора помогает структурировать код таким образом, чтобы он хорошо работал в настройках распределенной обработки, а исходные API-интерфейсы предоставляют вам доступ к расширенным возможностям платформы. . Но если ваш коннектор очень простой и не требует ни того, ни другого, то вы можете просто собрать коннектор из других встроенных преобразований.

В: Предположим, я решил использовать Source и Sink. Тогда как мне упаковать коннектор в виде библиотеки: нужно ли просто предоставить класс Source или Sink или обернуть его в PTransform?

A: Коннектор в конечном итоге должен быть упакован как PTransform, чтобы пользователь мог просто p.apply() в своем конвейере. Однако внутри ваше преобразование может использовать классы Source и Sink.

Распространенным шаблоном является предоставление классов Source и Sink, используя шаблон Fluent Builder и позволяя пользователю обернуть их в Read.from() или Write.to() преобразование, но это не является строгим требованием.

person jkff    schedule 11.01.2016
comment
коннекторы, которые откуда-то читают, как правило, PTransform<PInput, PCollection<T>> - эта информация устарела? В Beam 0.6.0 PTransform<PBegin, PCollection<T>> намного больше, чем PTransform<PInput, PCollection<T>> - person wtanaka.com; 26.03.2017
comment
Спасибо, исправил свой ответ. - person jkff; 26.03.2017