Apache Arrowフォーマットはnなぜ速いのか

: author

須藤功平

: institution

株式会社クリアコード

: content-source

db tech showcase ONLINE 2020

: date

2020-12-08

: start-time

2020-12-08T15:30:00+09:00

: end-time

2020-12-08T16:10:00+09:00

: theme

.

Apache Arrowと私

* 2016-12-21に最初のコミット
* 2017-05-10にコミッター
* 2017-09-15にPMCメンバー
* 2020-11-25現在コミット数2位(508人中)

Apache Arrow

* データ分析ツールの基盤を提供
* ツールで必要になるやつ全部入り
* 各種プログラミング言語をサポート

全部ってなに!?

(('tag:left')) (('tag:wrap-word-char')) (('tag:justify')) データフォーマットとかそのデータを高速処理する機能とか他の各種データフォーマットと変換する機能とかローカル・リモートにあるデータを透過的に読み書きする機能とか高速RPCとかなんだけど、全部を説明すると「すごそうだけどよくわからないね!」と言われる!

今日のトピック

Apache Arrownフォーマット

Apache Arrowフォーマット

* データフォーマット
  * 通信用とインメモリー用の両方
* 表形式のデータ用
  * =データフレーム形式のデータ用
* 速い!

速い!

* データ((*交換*))が速い!
* データ((*処理*))が速い!

データ交換が速い!

(('tag:center')) (('tag:margin-bottom * -0.5')) Apache Arrowフォーマットにすると高速化!

# image
# src = images/apache-arrow-and-data-interchange.svg
# relative-height = 100

利用事例:Apache Spark

# image
# src = images/apache-arrow-and-apache-spark.svg
# relative-height = 100

スライドプロパティー

: enable-title-on-image

false

利用事例:Amazon Athena

# image
# src = images/apache-arrow-and-amazon-athena.svg
# relative-height = 100

スライドプロパティー

: enable-title-on-image

false

利用事例:RAPIDS

# image
# src = https://docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf
# page = 3
# relative-height = 130
# relative-clip-y = 15
# relative-clip-height = 70

(('tag:right')) (('tag:margin-top * 6')) (('note:((<URL:docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf#page=3>))'))

スライドプロパティー

: enable-clear-blue-slide-body-vertical-centering

false

: enable-title-on-image

false

利用事例:RAPIDS

# image
# src = https://docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf
# page = 8
# relative-height = 120
# relative-clip-y = 15
# relative-clip-height = 80

(('tag:right')) (('tag:margin-top * 5')) (('note:((<URL:docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf#page=8>))'))

スライドプロパティー

: enable-clear-blue-slide-body-vertical-centering

false

: enable-title-on-image

false

どうして速いの?

* シリアライズコストが低い
  * すぐに送れるようになる
* デシリアライズコストが低い
  * 受け取ったデータをすぐに使えるようになる

シリアライズ処理

(1) メタデータを用意
(2) メタデータ+元データそのものを送信
    * 元データを加工しないから速い!
    * なにもしないのが最速!

元データを加工する例:JSON

0x01 0x02(8bit数値の配列)
   ↓
"[1,2]"(JSON)
0x01→0x49(数値→ASCIIの文字:'1')
0x02→0x50(数値→ASCIIの文字:'2')

元データそのものを使うと…

* 変換処理にCPUを使わなくてよい
  * 速い
* 変換後のデータ用のメモリー確保ゼロ
  * 大きなメモリー確保はコストが高い
  * 一定の作業領域を使い回すとかしなくてよい
  * 速い

デシリアライズ処理

(1) メタデータをパース
(2) メタデータを基に元データを取り出す
    * 元データをそのまま使えるから速い!
    * なにもしないのが最速!

元データを元に戻す例:JSON

"[1,2]"(JSON)
   ↓
0x01 0x02(8bit数値の配列)
0x49→0x01(ASCIIの文字:'1'→数値)
0x50→0x02(ASCIIの文字:'2'→数値)

元データを取り出せると…

* 変換処理にCPUを使わなくてよい
  * 速い
* 変換後のデータ用のメモリー確保ゼロ
  * すでにあるデータをそのまま使うのでゼロコピー
  * 速い
* メモリーマップで直接データを使える
  * ディスク上のメモリー以上のデータを扱える

{,デ}シリアライズコスト

* Apache Arrowフォーマット
  * ほぼメタデータのパースコストだけ
* それ以外の多くのフォーマット
  * データ変換処理(CPU)
  * 作業用メモリー確保処理(メモリー)

データ交換が速い!

(('tag:center')) (('tag:margin-bottom * -0.5')) Apache Arrowフォーマットにすると高速化!

# image
# src = images/apache-arrow-and-data-interchange.svg
# relative-height = 100

利用事例:Apache Spark

# image
# src = images/apache-arrow-and-apache-spark.svg
# relative-height = 100

スライドプロパティー

: enable-title-on-image

false

利用事例:Amazon Athena

# image
# src = images/apache-arrow-and-amazon-athena.svg
# relative-height = 100

スライドプロパティー

: enable-title-on-image

false

利用事例:RAPIDS

# image
# src = https://docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf
# page = 8
# relative-height = 120
# relative-clip-y = 15
# relative-clip-height = 80

(('tag:right')) (('tag:margin-top * 5')) (('note:((<URL:docs.rapids.ai/overview/RAPIDS%200.15%20Release%20Deck.pdf#page=8>))'))

スライドプロパティー

: enable-clear-blue-slide-body-vertical-centering

false

: enable-title-on-image

false

データサイズは?

* CPU・メモリーにやさしくて速いんだね!
* じゃあ、データサイズはどうなの?
  * 大きいとネットワーク・IOがボトルネック
  * 本来のデータ処理を最大限リソースを使いたい
  * データ交換をボトルネックにしたくない

データサイズ

* 別に小さくない
  * 元データそのままなのでデータ量に応じて増加
* Zstandard・LZ4での圧縮をサポート
  * ゼロコピーではなくなるがサイズは数分の1
  * 圧縮・展開が必要→元データそのものを使えない
  * CPU・メモリー負荷は上がるが\n
    ネットワーク・IO負荷は下がる
  * ネットワーク・IOがボトルネックになるなら効く

圧縮時のデータサイズと読み込み速度

  # image
  # src = https://ursalabs.org/20200414_file_sizes.png
  # align = left
  # vertical-align = top
  # relative-width = 75

# image
# src = https://ursalabs.org/20200414_read_py.png
# align = right
# vertical-align = bottom
# relative-width = 75
# relative-clip-y = 12
# relative-margin-top = 12
# relative-margin-left = -3.8

(('tag:right')) (('tag:margin-top * 15')) (('note:((<URL:ursalabs.org/blog/2020-feather-v2/>))'))

スライドプロパティー

: enable-clear-blue-slide-body-vertical-centering

false

: enable-title-on-image

false

データ交換が速い!のまとめ

* {,デ}シリアライズが速い
  * 元データをそのまま使うので処理が少ない
  * CPU・メモリーにやさしい
* 圧縮もサポート
  * ネットワーク・IOがボトルネックならこれ
  * CPU・メモリー負荷は上がるが\n
    データ交換のボトルネックを解消できるかも

交換したデータの扱い

* データ分析はデータ交換だけじゃない
  * データ交換だけ速くしても基盤とは言えない
* データ処理も速くしないと!
  * データ処理を速くするにはデータ構造が大事

高速処理のためのデータ構造

* 基本方針:
  * 関連するデータを近くに置く
* 効果:
  * CPUキャッシュミスを減らす
  * SIMDを活用できる

データ分析時の関連データ

* 分析時はカラムごとの処理が多い
  * 集計・ソート・絞り込み…
* 同じカラムのデータを近くに置く
  * カラムナーフォーマット

カラムナーフォーマット

# img
# src = images/columnar.svg
# relative_height = 100

スライドプロパティー

: enable-title-on-image

false

各カラムでのデータの配置

* 関連するデータを近くに置く
* 定数時間でアクセスできるように置く
* SIMDできるように置く
  * アラインする\n
    (('note:アライン:データの境界を64の倍数とかに揃える'))
  * 条件分岐をなくす

真偽値・数値のデータの配置

固定長データなので連続して配置
32ビット整数:[1, 2, 3]
0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x03 ...

文字列・バイト列:データの配置

実データバイト列+長さ配列に配置
UTF-8文字列:["Hello", "", "!"]
実データバイト列:"Hello!"
長さ配列:[0, 5, 5, 6]
i番目の長さ:長さ配列[i+1] - 長さ配列[i]
i番目のデータ:
  実データバイト列[長さ配列[i]..長さ配列[i+1]]
注:長さ→データ→長さ→データ→…で置くと
    定数時間でi番目にアクセスできない

nullと条件分岐

* null対応のアプローチ:
  * null値:Julia: ((<(({missing}))|URL:https://docs.julialang.org/en/v1/manual/missing/>)), R: ((<(({NA}))|URL:https://cran.r-project.org/doc/manuals/r-release/R-lang.html#NA-handling>))
  * 別途ビットマップを用意:Apache Arrow
* ビットマップを使うと条件分岐をなくせる

nullと条件分岐とSIMD

# img
# src = images/simd-null.svg
# relative_height = 100

スライドプロパティー

: enable-title-on-image

false

nullと条件分岐とSIMD

# image
# src = https://wesmckinney.com/images/bitmaps_vs_sentinels.png
# relative-height = 90

(('tag:right')) (('note:((<URL:wesmckinney.com/blog/bitmaps-vs-sentinel-values/>))'))

スライドプロパティー

: enable-clear-blue-slide-body-vertical-centering

false

: enable-title-on-image

false

高速なデータ処理のまとめ

* 高速なデータ処理にはデータ構造が重要
  * データ分析にはカラムナーフォマットが適切
* 定数時間でアクセス可能なデータの配置
* SIMDにやさしいデータの持ち方
  * アライン・null用のビットマップ

まとめ

* Apache Arrow
  * なんかデータ分析に便利そうなすごいやつ!
  * 「よくわからん」と言われるからといって\n
    全体像を説明してもらえなかった!
  * 使い方も説明してもらえなかった!
* Apache Arrowフォーマット
  * これだけ説明してもらえた!

まとめ:Apache Arrowフォーマット

* Apache Arrowフォーマット
  * 通信用・インメモリー用のデータフォーマット
  * 表形式のデータ用
* Apache Arrowフォーマットは速い
  * データ((*交換*))が速い
  * データ((*処理*))が速い
  * データ交換してすぐに高速処理できるフォーマット

まとめ:なぜデータ交換が速いのか

* 元データをそのままやりとりできるから
  * {,デ}シリアライズコストが低い
  * CPU・メモリーにやさしい
* ネットワーク・IOの負荷を下げたい
  * Zstandard・LZ4による圧縮
  * CPU・メモリー負荷は上がるが\n
    ネットワーク・IO負荷は下がる

まとめ:なぜデータ処理が速いのか

* 最適化されたデータ構造
  * カラムナーフォーマット
  * SIMDを使えるデータの持ち方
* 最適化された実装
  * (('wait'))今回は紹介していない!!!

次回予告!

* 案1:Apache Arrowデータの高速処理
* 案2:Apache Arrowデータの高速RPC
* 案3:○○言語でApache Arrowを使う方法
* ...

次のステップ

* もっと詳しく知りたくなったから\n
  イベント・社内・…で紹介して!
  * ((<URL:https://www.clear-code.com/contact/>))
* 使いたくなったから技術サポートして!
  * ((<URL:https://www.clear-code.com/contact/>))
* Apache Arrowの開発に参加したい!
  * ((<URL:https://arrow.apache.org/community/>))