Apache Arrow勉強会に参加しました #osaka_arrow

arrow

はじめに

2017/05/28 クラスメソッド大阪オフィスにてApache Arrow勉強会が開催されました。たまたま先日の勉強会から引き続き、大阪に滞在していたため、こちらに参加してきました。そのレポートになります

開催概要

GoでApache Arrowをやってみた話

西田さん@クラスメソッド株式会社のLTです。結果として最後までできませんでしたが、どこで詰まったか、どのように試行錯誤したかを七転八倒している様子を交えつつの発表でした。

  • Goのネイティブ実装はバインディングはない
  • C++のバインディングを利用するとGoでArrowが使える
  • Go-gir-generatorでグルーコードを吐き出す
  • OSXだとどうしても動かない部分があった
  • Docker+Ubuntuで再挑戦
  • パッケージインストールがあることに気づかず、ソースからコンパイル。そして当日の午前三時
  • 3時間くらい詰まっていた箇所を須藤さんに質問したら30秒で解決。

Apache Arrow

株式会社クリアコードの須藤功平さんが、データ分析向けの次世代フォーマットであるApache Arrowについて、概要から詳細までさらには開発への参加方法までを紹介してくれるセッションでした。

  • RubyもApache Arrowでデータ処理の仲間入り
  • ハッシュタグは #osaka_arrow
  • 全員10秒くらいの自己紹介
    • 普段使ってる言語、データ分析してるかどうか?
    • 参加者の利用言語。R, Python, Ruby, Spark, C#, Java, JavaScript, Go, Rust, node, php, C, C++, Drill, Scala
    • データ分析をやっている人も半数ほど
  • Arrowはデータフォーマットの仕様。仕様だけだと使えないのでライブラリも提供
    • 各システムを連携する際のデータ交換コストが高いのを低くしたい
    • 重複した最適化実装を共有する。それぞれのシステムでチューニングするのは無駄。
    • メモリにいい感じにデータを配置して高速に処理できるようにするところを共通化してしまおう。
  • システム間のデータ交換の際に、シリアライズ・パースに使うリソース(CPU)がもったいない。そんなところにCPUパワーを食うならもっと本質的なところへフォーカスしたい。

【今現在】 各システムごとにデータをシリアライズ・パースしてやり取りしてる。 https://arrow.apache.org/

【理想の姿】 Arrowの形式に統一するとシリアライズ・パースといった処理がいらない

  • コスト0のシリアライズ・パース(理想)
    • 例:int8をメモリ上にシーケンシャルに配置。
  • Arrowのトレードオフ。 圧縮率よりシリアライズのコストが低くなることを優先。
  • 例:PySparkの高速化:Py↔Javaのデータ交換コストを激減させる
    • PythonはC++実装のバインディングを使って読み込んでる
    • PythonでArrow形式で出力したものをRubyで読み込む(こちらもC++実装のバインディングを利用して)
    • Luaでも使える(Torch)

Feather

  • Feather:R@ RとPythonでもっと効率的に使えるように作ってる。Arrowの作者と同じ
  • Rubyでも使える(Feather)

Parquest

  • 保存に特化した形式。圧縮率優先であるため、シリアライズにCPUパワーがかかっても圧縮率高い方を選ぶ
  • Hadoop界隈でよく使ってる
  • ビッグデータ分析ではよく使われてる
  • Q. ファイルサイズが小さくなるっていう認識で良い?
    • A. (圧縮率優先なので)Arrowよりかは小さいのは間違いない
  • Q. テキストファイルより変換後の方がファイルサイズが大きくなってしまってるのだけど?
    • A. 圧縮設定がかかってないかも。同じ文字列は一箇所に集めて、このバイトからこのバイトまでみたいなオフセット指定をすることが出来るため、サイズがガッと小さくなる
  • Arrowで受け取ったデータをまたばらして効率悪く処理するのではなく、良い感じに効率よく処理して、効率よく出力出来たほうが良いよね。

多次元配列

  • ArrowではOption項目
  • テンソル。要素は全て同じ型である
  • C++実装ではサポート。バインディングで使える。Python, Ruby, Luaでは使える。
  • Javaではまだ対応していない

Arrowの詳細

  • カラム型データ。そのためある特定の項目に対する集計などは非常に早い。
  • 並列処理で暇な人がいないように実行していく
  • Arrowはデータ構造を工夫してCPUに優しく
  • Record Batch: ビッグデータは一気に扱えないので、ちょっとずつ使うためのデータのグループ。いい感じのサイズでデータをちょっとずつ処理する。小さなデータ1個ずつでもいいけどそれはオーバーヘッドが大きすぎるので効率が悪い。

データレイアウト

  • 基本的に 配列で何でもかんでも表現する方針
  • Nullビットマスク配列 でNullableを表現
  • メモリレイアウトごと渡すので、別にシリアライズとかいらない

並列処理

  • Arrowでブランチングを回避。すると判断する必要がなくなるので並列処理がぶん回せる

対応状況

  • 当初の予定よりかは遅れてるけど、現状それぞれ頑張っている

Arrow詳細

  • Zero-copy コピーもコストがかかるので、ここを極力最小化するのを目指す
  • データはRead-only制約の状態になっている
  • ディスクI/OはインメモリのI/Oに比べて低速。インメモリにデータを置けるなら次に問題になるのはCPU処理の効率を上げる必要がある
  • Q. Record Batchサイズは自動的に決めてくれるわけではない?
    • A. そこまではやってくれないので設定しないとダメ
  • Q. 巨大なデータをArrowにどうやって変換してリモートに送るの?
    • A. ローカルで渡す時にはメモリファイルシステムに書き込む。リモートで利用するなら、まずデータを通信経路を使ってコピーしてリモート先で使う。この場合はどうしてもコピーしないと無理。
    • A. Arrowはあんまりローカルとかリモートとかそういったものはあんまり考慮していない

PySparkの場合

  • SparkはJVMなのでJavaで動いてる。Pythonでなんかしたい時にSparkのデータ形式を呼ぼうとするとJVMの形式からPythonの形式に変換する必要があるけどここがめっちゃ非効率。ここをチューニングするけど各システムそれぞれにチューニングするのは色々と非効率。

  • Q. Zero-Copyは良いと思うけど、実際は難しいのでは。なんかお作法とかあるの?

    • A. ArrowがそのメモリレイアウトのフォーマットなのでArrowに従う。演算とかはArrowが今後作っていく。データ分析なので 数値処理 であることが前提なので汎用的なものは作れるはず

今後やっていくこと

  • データフレーム処理の最適化実装。Arrowを使って効率的に処理させるのは各言語の実装に依存してる。今後はその辺の処理もArrowが出来ると良い
  • マルチコア・GPU対応
    • GPUデータフレームをやってる人もいる。仕様だけを使って作っている
  • xtensor: Numpyと同じようなやつをC++でやろう。
  • Pandasで出来た便利機能が今後使えるようになると思う。
  • Weld: GPU用のLLVM。これもArrow対応を進めている
  • Q. バイトオーダーが異なるものは対応している?
    • A. 今はIntelのしかダメかも

開発に参加しましょう

  • Apache Arrowの旨味
    • みんなが使うと初めて旨味が出てくる
  • Q. 使いたい人はどうすれば?
    • A. 待ってるより自分の欲しい機能を開発していきましょう。
  • Apache Arrow関連の開発に参加。
  • Q. Clouderaとの関係は?
    • A. わだかまりとかは特にない。言語とか会社とかの垣根を取っ払って、みんなハッピーになるためにやってるプロジェクト
  • Q. Apacheのプロジェクトになったのはいつ?
    • A. Apache Arrowのプロジェクトになったのは2016年2月

開発への参加手引

  • JIRA: コミットは全てチケットに紐づく。こういうのやりたい系もチケットになる(GPUを使ってArrowでやるっていうのもチケットになってる)
  • ML: ここでディスカッションをしている。JIRAの新チケットも流れてくる
  • バグレポート: JIRAチケット作成
  • バグ修正・機能追加: JIRAにチケット作成し、GithubでPRする。
  • 相談: ML

モジュール

  • Java: Java実装
  • C++: C++実装
  • GLib: C++実装のCラッパー(各言語バインディング向け)
  • JS: JavaScript実装: TypeScriptを利用
  • R: C++実装のRcppラッパー(未着手)
  • Go: Go実装(GLibがあるけどネイティブ実装の方がオーバーヘッドがなくて良い)
  • Rust: Rust実装(バインディングを作っている人がいるけど止まってる)
  • GLibは須藤さんがコミッターの権利もらえそうなのでPRすると良いかも

Apache Arrow関連開発

大量のデータ交換が必要なものをArrow対応させる。

  • Apache Spark(PySparkはすでに進行中)
  • Groonga: 対応済み
  • Ray: 対応済み

Red Data Tools

  • 絶賛開発しているRuby用データ分析ツール。Apache Arrowベース
  • Ruby以外でも使えるようにしたい
  • GLibバインディングとして開発。Luaとかでも使えるように。専用バインディングとして開発しない
  • 参考例: parquet-glip, xtensor-glib

質疑応答

発表中にも都度質疑応答があったため、若干順不同です。

  • Q. データ分析以外でも使えるの?
    • A. Fluentdとか?Rubyのオブジェクト作らなくていいので効率が良いかも。
  • Q. DBとどのように絡めるか
    • A. Arrow形式は保存用の形式ではない。あくまで処理を高速に行うために特化しているので、集計結果を保存したりする場合は、Arrowの形式じゃないほうが良い

登壇資料

感想

今まであまり意識したことがなかったですが、確かにシステム間のやりとりをする際に、JSONなどの文字列にシリアライズし、使いたい方はそのデータをパースして自分たちのシステム内部表現へ変換するというプロセスは非常に無駄だと思いました。特に膨大なデータを分析する際にはCPUの性能を100%分析に利用するためには、無駄を削ぎ落とすことは非常に大切なことかと思います。メモリレイアウトを定義してシステム間の差異をなくす、ReadOnly、Zero-Copyなどのアイデアは非常に興味深いものでした。今はデータ分析を中心に利用されることを目指しているようです。

まだまだ生まれたてで活発に開発が行われているようですので、使いたいなと思った方は、是非自分の 使いたいもの を開発する側に回ってみてはいかがでしょうか。

参照