Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
ZIOでサクッとFunctionalにETL
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
wakye5815
September 06, 2024
2.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ZIOでサクッとFunctionalにETL
wakye5815
September 06, 2024
More Decks by wakye5815
See All by wakye5815
LintのみでAIに開発スタイルを叩き込めるのか?
wakye5815
4
4.7k
sbt-assemblyにハマってDB接続できず時間が溶けた話
wakye5815
1
1.9k
Featured
See All Featured
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
890
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
590
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
660
The untapped power of vector embeddings
frankvandijk
2
2k
Embracing the Ebb and Flow
colly
88
5.2k
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1.1k
Un-Boring Meetings
codingconduct
0
480
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
2
340
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
870
Transcript
ZIOでサクッとFunctionalにETL 2024/09/06 Scalaわいわい勉強会 #3 wakye5815 1
自己紹介 Scalaでバックエンド書いたりEM見習いを始めたり色々やってます 名前:脇田悠介 働いてるところ:株式会社Flinters X :@wakye5815 悩み:ZIOの読み方がZIOかZIOなのかわからない 2
とある日 3
実装依頼はいつも突然に 大量の広告配信データを〜 ちょろっと圧縮して〜 ストレージに出力する〜 使い捨ての〜 スクリプトお願いします! 4
欲しいのは ストリーミング操作が優秀でサクッと書ける 軽量に動かせて 並行処理もいい感じ あわよくばFunctionalな そんなScalaライブラリ 5
そんなScalaライブラリあるわけ.... 6
7
と言うことで今日は軽量ETL by ZIOに ついて話します 8
他ライブラリ候補 9
Akka/Pekko Stream メリット 様々なデータソースを接続できるAlpakka優秀 ストリーミング操作のオペレーターもかなり揃っている 腐っているので情報が多い デメリット ActorSystemが付いてくる チームでは脱Akkaしていたので改めて採用するのも... 10
Spark メリット 分散処理できてスケールする Alpakkaと同じくデータソースサポートが手厚い デメリット クラスタ管理はちょっとしたくない 11
そしてZIO ZIOはEffectライブラリ 誤解を恐れずに表現するとZIO文脈のEffectは R => Either[E,A] であり ZIO[R,E,A] として扱われる ScalaらしくFunctionalに設計されているがモナモナしていないので
とっつきやすい、またドキュメントも十分 並行処理はJVMのvirtual threadをベースとしたFiberを提供してい る 12
Streamingはどうなの? ZIOを元にしたZIO Streamsが提供されている Akka/Pekkoに負けない抽象化され且つ豊富なストリーミング操作 ZIO Streamsはプッシュベースストリームではなくプルベースストリ ームのためバッファリング要らず、バックプレッシャーしなくてOK ただしAlpakkaほどの豊富なデータソースサポートはないので要件 とご相談 13
顧客が本当に求めていたもの 14
結果としてZIOを採用 Httpな広告媒体APIからデータをとるだけなのでデータソースサポ ートが豊富でなくてもOK 使い捨てなのでSparkではオーバーキル チーム背景も含めてAkka/Pekkoはごめん 15
実装していく 16
まずは今回のETLについて Extract 広告媒体APIから取得できる配信データをExtract Transform 取得したデータを一定粒度でgzipに圧縮 Load 外部のシステムが読みにくるGCSにLoad 17
ZIO Streamsで表現するには ワークフロー定義に3つの抽象化されたモジュールを利用する ZStream[Env,Err,Out] ストリームワークフローのデータソースとして機能 ZPipeline[Env, Err, In, Out] 実態は
ZStream[Env,Err,In] => ZStream[Env,Err,Out] ZSink[Env,Err,In,Left,Consumed] ZSink[Env,Err,In,Left,Consumed] => ZIO[Env,Err,Consumed] な ZStream#run に渡して消費する 18
組み合わせると def extractionStream(apiEndpoint: URL): ZStream[Any, Throwable, ApiResponse] def transformationPipeline: ZPipeline[Any,
Throwable, APIResponse, (String, Array[Byte])] def loadingSink: ZSink[Any, IOException, (String, Array[Byte]), Nothing, Unit] object Main extends ZIOAppDefault override def run = val effects = apiEndpoints.map { apiEndpoint => extractionStream(apiEndpoint) >>> transformationPipeline >>> loadingSink } ZIO.collectAllPar(effects).unit 19
Extractの実装 java.util.concurrent.FutureあるいはBlockingなAPI実行をZIO Effectに変換する APIはpagination形式 paginateしつつ変換したZIO EffectをさらにStreamへ変換 20
Extractの実装 def extractionStream(apiEndpoint: URL): : ZStream[Any, Throwable, ApiResponse] = ZStream.paginateZIO(apiEndpoint)
{ apiEndpoint => for response: Task[ApiResponse] <- if(isBlocking(apiEndpoint)) then ZIO.attemptBlocking(callBlockingApi(apiEndpoint)) else ZIO.fromFutureJava(callApi(apiEndpoint)) nextEndpoint = Option(response.nextEndpoint) yield (response, nextEndpoint) } 21
Transformの実装 ZStreamで流れてくるApiResponseをArray[Byte]に変換 ArrayButeをgzip圧縮する ついでにuploadする粒度毎にファイル名をつけておく 22
Transformの実装 def transformationPipeline: ZPipeline[Any, Throwable, APIResponse, (String, Array[Byte])] = val
gzipPipeline = ZPipeline.mapZIO { (response: APIResponse) => ZIO.scoped { for byteArrayOs <- ZIO.fromAutoCloseable(ZIO.attempt(new ByteArrayOutputStream())) gzipOs <- ZIO.fromAutoCloseable(ZIO.attempt(new GZIPOutputStream(byteArrayOs))) _ <- ZIO.attemptBlockingIO(gzipOs.write(response.getRawResponse.getBytes)) yield byteArrayOs }.map(_.toByteArray) } val fileNamePipeline = ZPipeline.mapAccum[Array[Byte], Int, (String, Array[Byte])](1)( (index, data) => (index + 1, (s"data_$index.json.gz", data)) ) gzipPipeline >>> fileNamePipeline 23
Loadの実装 あとはGCSに放り込むだけ 24
Loadの実装 def loadingSink: ZSink[Any, IOException, (String, Array[Byte]), Nothing, Unit] =
ZSink.foreach { (pathWithData: (String, Array[Byte])) => val blobId = BlobId.of(BUCKET_NAME, pathWithData._1) val blobInfo = BlobInfo.newBuilder(blobId).build() ZIO.attemptBlockingIO(storage.create(blobInfo, pathWithData._2)) } 25
ZIO Streams万歳 26
他にも Streamに対するretry stream.retry(Schedule.exponential(1.second)) timeoutしたら他のStreamに切り替える firstStream.timeoutTo(10.seconds)(secondStream) 27
まとめ モナモナせずにFunctionalにETLを組めた ZStream(むしろZIO)の豊富なオペレータでデータ処理のロジックが スマートに Akka/Pekko Streamを使っていた人はZStreamの操作自体は似てい るので移行しやすそう 28
We're hiring 絶賛採用中なのでZIOやりたい人、大規模広告データと戯れたい人い らっしゃいましたらお話ししましょう〜 https://www.wantedly.com/companies/flinters 29