Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dataflow with Scala

B8ab2e500b13247ede10b3ed06012b3a?s=47 laughingman7743
September 12, 2018

Dataflow with Scala

B8ab2e500b13247ede10b3ed06012b3a?s=128

laughingman7743

September 12, 2018
Tweet

Transcript

  1. 2018/09/12 GCPUG Tokyo Dataflow Day September 2018 @laughingman7743 Dataflow with

    Scala
  2. 2 自己紹介 Copyright © Merpay, Inc. All Rights Reserved. @laughingman7743

    Data Platform Team at Merpay
  3. アジェンダ Scio 01 Scio REPL 02 Beam との比較 03 テンプレート化

    04 実装の参考になりそうなリポジトリ 05 まとめ 07 Merpay での利用 06
  4. Scio

  5. Scio • Spotify が OSS で公開している ApacheBeam の Scala ラッパー

    • Ecclesiastical Latin IPA /ˈʃi.o/, [ˈʃiː.o], [ˈʃi.i̯o] • Verb I can, know, understand, have knowledge. • コレクション操作する感覚で Dataflow を書くことができる (DoFn, Apply 不要) • PCollection をラップした SCollection の操作
  6. SBT プロジェクトの始め方 • Giter8 テンプレートを使ってプロジェクトを作ると良い (SBT ムズカシイ) • REPL が使えるプロジェクトができる

    (sbt repl/run で起動) • Scalastyle の Lint も設定済み • IDE は IntelliJ がオススメ Scio IDEA https://plugins.jetbrains.com/plugin/8596-scio-idea アノテーションマクロを認識できるようになる IntelliJ プラグイン $ brew install sbt $ sbt new spotify/scio-template.g8 @BigQueryType.fromTable("publicdata:samples.gsod”) class Row @BigQueryType.fromQuery("SELECT tornado, month FROM [publicdata:samples.gsod]”) class Row
  7. Scio REPL

  8. DEMO

  9. Scio REPL • DEMOの内容 • REPLのみ使いたい場合は, brew でインストール • :paste

    モード便利 • DataflowRunner も使える scio> val shakespeare = sc.textFile("gs://dataflow-samples/shakespeare/hamlet.txt") scio> :paste scio> val wordCount = shakespeare.flatMap(_.split("[^a-zA-Z']+") .filter(_.nonEmpty)) .countByValue.map(_.toString) .saveAsTextFile("count.txt") scio> sc.close() scio> wordCount.waitForResult().value.take(3).foreach(println) $ brew tap spotify/public $ brew install scio $ scio-repl $ scio-repl --project=MY_PROJECT \ --stagingLocation=gs://MY_BUCKET/stg/ --tempLocation=gs://MY_BUCKET/tmp/ \ --runner=DataflowRunner
  10. Beam との比較

  11. Beam との比較 • 簡単な WordCount の例 https://github.com/spotify/scio/blob/master/scio-examples/src/main/java/org/apache/beam/examples/WordCount.java https://github.com/spotify/scio/blob/master/scio-examples/src/main/scala/com/spotify/scio/examples/WordCount.scala • コメントを除いた行数

    Scio 約40行, Beam 約120行 • Scio では変換処理を行う Function クラスの定義は不要 sc.textFile(input) .map { w => val trimmed = w.trim lineDist.update(trimmed.length) trimmed } .filter { w => val r = w.nonEmpty if (r) sumNonEmpty.inc() else sumEmpty.inc() r } .flatMap(_.split("[^a-zA-Z']+").filter(_.nonEmpty)) .countByValue .map(t => t._1 + ": " + t._2) .saveAsTextFile(output) static class ExtractWordsFn extends DoFn<String, String> { private final Counter emptyLines = Metrics.counter(ExtractWordsFn.class, "emptyLines"); private final Distribution lineLenDist = Metrics.distribution( ExtractWordsFn.class, "lineLenDistro"); @ProcessElement public void processElement(@Element String element, OutputReceiver<String> receiver) { lineLenDist.update(element.length()); if (element.trim().isEmpty()) { emptyLines.inc(); } String[] words = element.split(ExampleUtils.TOKENIZER_PATTERN, -1); for (String word : words) { if (!word.isEmpty()) { receiver.output(word); } } } } Scio Beam
  12. DoFn • DoFn もできる http://spotify.github.io/scio/examples/DoFnExample.scala.html sc.textFile(args.getOrElse("input", ExampleData.KING_LEAR)) .flatMap(_.split("[^a-zA-Z']+").filter(_.nonEmpty)) .applyTransform(ParDo.of(new DoFn[String,

    Int]{ @Setup private[extra] def setup(): Unit = Unit @StartBundle private[extra] def startBundle(c: DoFn[String, Int]#StartBundleContext): Unit = Unit @ProcessElement private[extra] def processElement(c: DoFn[String, Int]#ProcessContext): Unit = c.output(c.element().length) @FinishBundle private[extra] def finishBundle(c: DoFn[String, Int]#FinishBundleContext): Unit = Unit @Teardown private[extra] def teardown(): Unit = Unit })) .saveAsTextFile(args("output”))
  13. テンプレート化

  14. テンプレート化 • 実行時に変更になりそうな値をパラメータ化 (input, output 等) • パラメータを変更するだけでジョブを使い回せる仕組み • テンプレート化コマンド

    • テンプレートを指定したジョブの実行 input パラメータはそのままで, output パラメータ の値を FOOBAR に変更して実行 複数のパラメータを変更する場合はカンマ区切りで指定 sbt "runMain xxx.yyy.MyPipeline \ --runner=DataflowRunner --region=us-central1 \ --streaming=true --project=MY_GCP_PROJECT_NAME \ --tempLocation=gs://MY_BUCKET/tempLocation/MyPipeline \ --templateLocation=gs://MY_BUCKET/templateLocation/MyPipeline \ --input=MY_INPUT --output=MY_OUTPUT" gcloud dataflow jobs run MyPipeline \ --project MY_GCP_PROJECT \ --gcs-location gs://MY_BUCKET/templateLocation/MyPipeline \ --parameters output=FOOBAR
  15. コマンドライン引数とテンプレートパラメータ (1/2) • ContextAndArgs だとコマンドライン引数しか対応できない • Beam の PipelinesOptions を継承した

    trait を作成 • コマンドライン引数をパースするコンパニオンオブジェクトを作る trait MyPipelineOptions extends PipelineOptions { def getInput: ValueProvider[String] def setInput(value: ValueProvider[String]): Unit def getOutput: ValueProvider[String] def setOutput(value: ValueProvider[String]): Unit def getWindowSize: ValueProvider[Int] def setWindowSize(value: ValueProvider[Int]): Unit } object ContextAndOptsAndArgs { def apply[T <: PipelineOptions: ClassTag](cmdlineArgs: Array[String]): (ScioContext, T, Args) = { val (opts, args) = ScioContext.parseArguments[T](cmdlineArgs) val sc = ScioContext(opts) (sc, opts, args) } }
  16. コマンドライン引数とテンプレートパラメータ (2/2) • ContextAndArgs と同じ使い方 コンテキスト, パイプラインオプション, コマンドライン引数の3つが tuple で返却される

    opts からコマンドライン引数 もしくは パラメータで指定した値が取得できる • ローカルでは IntelliJ からコマンドライン引数を指定, GCP 環境ではテンプレート化してパラメータを指定 • コマンドライン引数とテンプレートパラメータの相互運用ができるように val (sc, opts, args) = ContextAndOptsAndArgs[MyPipelineOptions](cmdlineArgs)
  17. 実装の参考になりそうなリポジトリ

  18. 実装の参考になりそうなリポジトリ • Scio Example (Beam での実装と比較できる) https://github.com/spotify/scio/tree/master/scio-examples/src http://spotify.github.io/scio/examples/ コードスニペット (Scalding,

    Scio, Spark での実装を比較できる) https://github.com/spotify/big-data-rosetta-code • Beam + Scala ランダムサンプリングツール https://github.com/spotify/ratatool DBデータエクスポートツール https://github.com/spotify/dbeam Spotify 強い !
  19. Merpay での利用

  20. Merpay での利用 • スピードレイヤ (ストリーミング処理) で Scio を利用 • Scio

    と ScalaPB を使ったパイプライン https://speakerdeck.com/laughingman7743/scalatezuo-rutetahaihurain
  21. まとめ

  22. Scalaで書くメリット 簡潔な記述で複雑な処理を書くことができる 01 豊富なコレクション操作メソッド, 強力なパターンマッチング 02 Option, Try, Either 等エラーハンドリングがしやすい

    03 ジェネリックプログラミング (型安全で再利用しやすいクラス) 04 関数型プログラミングはほどほどに (ベターJavaとしての利用) 05
  23. Q&A