Apache Arrowの最新情報(2020年7月版) - 2020-07-31 - ククログ

ククログ

株式会社クリアコード > ククログ > Apache Arrowの最新情報(2020年7月版)

Apache Arrowの最新情報(2020年7月版)

Apache ArrowPMC(Project Management Commitee、プロジェクト管理チームみたいな感じ)のメンバーの須藤です。

みなさんはApache Arrowを知っていますか?最近、ついに1.0.0がリリースされたんですよ。私がApache Arrowの最新情報をまとめた2018年9月から毎年「今年中に1.0.0がでるぞ!」と言っていた1.0.0がついにリリースされたんです!

1.0.0を機に安心して使えるようになります。(どう安心なのかは後で説明します。)

Apache Arrowはすでにデータ処理界隈で重要なコンポーネントになりつつありますが、数年後にはもっと重要になっているだろうプロジェクトです。データ処理界隈に興味がある人は知っておくと役に立つはずなので毎年Apache Arrowの最新情報をまとめています。1.0.0がリリースされたので2020年7月現在の最新情報を紹介します。

私は、PMCの中では唯一の日本人で、コミット数は2番目に多いので、日本ではApache Arrowのことをだいぶ知っている方なはずです。日本語でのApache Arrowの情報があまりないので日本語で紹介します。

ちなみに、英語ではいろいろ情報があります。有用な情報源はApache Arrowの公式ブログ公式メーリングリストやそれぞれの開発者のブログ・発表などです。開発者のブログの中ではUrsa Labs Blogの隔月の開発レポート(最近は隔月の開発レポートコーナーがありませんが…)がオススメです。Ursa Labsはスポンサーを集めてフルタイムでApache Arrowの開発をしている非営利の組織です。(という説明でそんなに間違っていないはず。)

この記事ではそれらの情報へのリンクも示しながら最新情報を紹介するので、ぜひ英語の情報も活用してください。

Apache Arrowが実現すること

Apache Arrowが実現することはプロジェクト開始当初から変わっていないので、Apache Arrowの必要性から知りたいという方はApache Arrowの最新情報(2018年9月版)を参照してください。まとめると次の通りです。

Apache Arrowは大量のデータを効率的にメモリー上で処理することを目指しています。そのためにしていることは次の通りです。

  1. データ交換・高速処理しやすいApache Arrowフォーマットの仕様を定義

  2. 各種言語用のApache Arrowフォーマットを読み書きするライブラリーを開発

  3. 大量のメモリー上のデータを高速処理するためライブラリーを開発

Apache Arrowが向いている用途は次の通りです。

  • 大量データの交換

  • メモリー上での大量データの分析処理

実は、1.0.0の前からすでにApache Arrowは利用され始めています。

たとえば、Apache SparkはJVMとPython・R間でのデータ交換にApache Arrowを使って10倍以上高速化しています。(データ量が大きいほど高速化できます。)

Amazon AthenaはApache ArrowフォーマットでAmazon Athenaにデータを提供できる機能を提供しています。

GroongaはApache Arrowフォーマットでのデータロードと検索結果の返却に対応しています。

Apache Arrowの現状

それでは、2020年7月現在のApache Arrowについて説明します。

まず、2020年7月24日にApache Arrow 1.0.0がリリースされました。1.0.0の特筆する点はApache Arrowフォーマットの安定性です。

Apache Arrowフォーマットの安定性

フォーマットの安定性というは、互換性が高い低いとか問題が多い少ないとかいう話ではなく、フォーマットの互換性をどう維持する方針なのかという話です。

これまではたまに互換性が壊れていました。たとえば、Apache Arrow 0.15.0でデータをアラインするためにパディングするように変更しました。これにより0.15.0で生成したデータを0.15.0より前のバージョンで読めなくなりました。Apache SparkはApache Arrow 0.15.0より前からApache Arrowに対応していたので、Apache Sparkでこの問題に遭遇したケースが多かったはずです。

1.0.0からは後方互換性と前方互換性を次のように維持します。セマンティックバージョニングに従っています。簡単に言うと、メジャーバージョンが上がったら互換性はない、マイナー・パッチバージョンが上がっただけなら互換性がある、です。互換性が壊れるのは大変なのはわかっているのでできるだけメジャーバージョンが上がらないように運用する予定ではあります。

注意する点は「Apache Arrowフォーマットのバージョン」と「Apache Arrowライブラリーのバージョン」は別だということです。Apache Arrowライブラリー2.3.1はApache Arrowフォーマット1.1.2を使うということが起こりうるということです。

後方互換性:

  • 新しいフォーマットバージョンに対応したライブラリーでは古いフォーマットバージョン用に生成したすべてのデータを読める

    • 例:フォーマットバージョン1.0.0用に生成したデータはフォーマットバージョン2.0.0に対応したライブラリーで読める
  • フォーマットバージョンのメジャーバージョンが変わらない限り、新しいフォーマットバージョン用に生成したデータは古いフォーマットバージョンに対応したライブラリーでも読める

    • 例:フォーマットバージョン1.3.0用に生成したデータはフォーマットバージョン1.0.0に対応したライブラリーで読める

    • 例:フォーマットバージョン2.0.0用に生成したデータはフォーマットバージョン1.0.0に対応したライブラリーで読めるかもしれないし読めないかもしれない(読めることは保証しない。後述の前方互換性も参照。)

前方互換性:

  • 新しいフォーマットバージョン用に生成したデータは、古いフォーマットバージョンに対応したライブラリーでは読める、あるいは、読めないことを検出できる(おかしく読むことはない)

    • 例:フォーマットバージョン2.0.0用に生成したデータは、フォーマットバージョン1.0.0に対応したライブラリーで読める

    • 例:フォーマットバージョン2.0.0用に生成したデータは、フォーマットバージョン1.0.0に対応したライブラリーで読めない場合は読めないことを検出する(おかしく読まない)

  • フォーマットバージョンのマイナーバージョンが挙がった場合は新しい機能が追加される

    • 例:フォーマットバージョン1.1.0でフォーマットバージョン1.0.0ではなかった型を追加
  • 新しい機能を使っていない場合は新しいフォーマットバージョン用に生成したデータを古いフォーマットバージョンに対応したライブラリーで読める

    • 例:フォーマットバージョン1.1.0用に生成したデータだが1.0.0の機能しか使っていない場合はフォーマットバージョン1.0.0に対応したライブラリーで読める

参考:Format Versioning and Stability

なお、1.0.0のリリース前にいつもより多くフォーマットの変更が入っています。たとえば、データをLZ4・Zstandardで圧縮する機能が入っています。同一ホスト上でメモリー上のデータをそのまま交換している場合(たとえばmmap()で同じアドレスを共有している場合)は圧縮・展開で速度が落ちるので意味はありませんが、Apache Arrow Flightで異なるホスト間でデータを交換したり、Featherフォーマットとしてデータをストレージに保存する場合はI/Oが減って高速になる場合があります。他の変更点はApache Arrow 1.0.0のリリースアナウンスを参照してください。

Featherフォーマットと聞いてびっくりした人のために補足しておくと、Featherフォーマットバージョン1は非推奨のままです。Featherフォーマット2はApache Arrow IPCファイルフォーマットのことです。Apache ArrowライブラリーのC++実装ではFeatherフォーマットバージョン1もバージョン2も読み書きできます。

フォーマットのバージョンを説明したのでライブラリーのバージョンも説明します。

Apache Arrowライブラリーのバージョン

Apache Arrowライブラリーのバージョンもセマンティックバージョニングに従います。従うのですが、しばらくは毎回メジャーバージョンが上がる予定です。つまり、1.0.0の次のバージョンは2.0.0です。

Apache Arrowライブラリーはまだまだ活発に機能追加・変更・修正をしているため、互換性を維持しながらでは開発スピードが落ちてしまうことを懸念してこうなっています。

今のところApache Arrowライブラリーは3ヶ月に1回程度のペースでリリースされているので今年中に2.0.0がでて、来年には3.0.0が出るようなペースです。

フォーマットのバージョンのところでも説明しましたが、ライブラリーのバージョンとフォーマットのバージョンは別々に管理し、フォーマットの(メジャー)バージョンはできるだけあげない(互換性を壊さない)方針で運用します。そのため、ライブラリーのバージョンとフォーマットのバージョンはどんどん離れていきます。たとえば次のような感じです。

  • 1.0.0の次のリリース

    • ライブラリーのバージョン:2.0.0

    • データフォーマットのバージョン:1.0.0

  • 1.0.0の次の次のリリース

    • ライブラリーのバージョン:3.0.0

    • データフォーマットのバージョン:1.0.0

Apache Arrowライブラリーは頻繁に互換性が壊れる前提になるのでライブラリーを利用する人はセマンティックバージョニングに合わせて依存情報を設定したほうがよいかもしれません。たとえば、PyPIからインストールするならpyarrow==1.*と指定して同じメジャーバージョンを使うようにするといった具合です。

ただ、古いバージョンを使い続けることになるとApache Arrowライブラリーの高速化や新機能の恩恵を受けられないので、定期的にアップグレードした方がよいです。クリアコードではApache Arrow関連の開発のサポートサービスを提供しているので、Apache Arrowを使いたいけど自分たちで対応し続けるのは不安という方はご相談ください。Apache Arrowに詳しい会社としてお手伝いします。(宣伝)

Apache Arrowライブラリーはいろんな言語ですぐに使える(「batteries-included」と自分たちで言うこともある)開発プラットフォームを提供しようとしています。1.0.0で大きく変わったバージョニングの説明をしたので、次は各言語の現状を説明します。

各言語ごとのApache Arrowライブラリーの現状

Apache Arrowの最新情報をまとめはじめて3年目になりますが、毎年、ソースを見ながら各言語の状況をまとめていました。が、それも去年で終わりです。公式ドキュメントでまとめはじめたのです!

表を見るとわかるのですが、Apache Arrowの仕様をすべて満たした実装はまだありません。C++実装が一番実装しているのですが、それでもいくつか未実装の機能があります。(表の列にないC・Python・R・Ruby実装はC++実装のバインディングなので実装範囲はC++実装に準じます。)

次に実装範囲が多いのがJava実装でC++実装ほどではないですがほとんど網羅しています。

Go・JavaScript・C#・Rust実装は基本機能はほぼ網羅しているといった感じです。(Rust実装に1つもチェックが入っていないのはまだ誰も埋めていないからなだけで、Rust実装はアクティブに開発が進んでいる実装の1つです。)

自分が使いたい言語の実装に自分が使いたい機能は実装されていたでしょうか?もし、まだ実装されていなくても大丈夫です。実装すればいいのです!Apache Arrowは「みんなバラバラに基盤を実装するんじゃなくて一緒に協力して基盤を実装した方がみんながうれしくなるよね!」という発想で開発が始まっています。未実装の機能があったら一緒に実装しましょう!

未実装の機能を自分たちで実装してApache Arrowを使い始めた例を紹介します。網屋さんが開発しているALogというログ収集製品ではデータのやり取りの一部にApache Arrowを検討していました。高速化のためです。しかし、C#実装にまだリスト型が実装されていませんでした。そこで、網屋の橋田さんは業務の一環としてリスト型の対応などを実装し、ALogで必要な機能を使えるようにしました。その結果、ALogでApache Arrowを使った高速化を実現できました。今後、日本でもApache Arrowの開発に参加する企業は増えていくでしょうが、網屋さんは先行している企業の1つです。

ちなみに、クリアコードは網屋さんがApache Arrowの開発に参加することを支援しました。未実装の機能を実装したいから支援して欲しいという方はご相談ください。(宣伝)

各言語の実装の状況をざっと説明したのでこの1年での変更点もざっと説明します。まずは計算関数です。

計算関数

Apache Arrowライブラリーは高速なデータ交換方法だけではなく、高速なデータ処理方法も提供しようとしています。高速なデータ処理に関しては、今のところ、2つのアプローチの開発が進んでいます。1つはGandivaという名前の式コンパイラーです。条件式や計算式をJITコンパイルして高速に実行できます。もう1つは計算関数(compute functions)と呼んでいる関数群です。計算関数は各計算処理を個別に使います。

Gandivaではユーザーがa + b * cという式を入力として実行できますが、計算関数はユーザーがa + bを実行し、その結果とcの掛け算を実行します。Gandivaの方が高レベルな機能を提供するのですが、Gandivaレベルでも計算関数が提供しているのと同レベルの機能(たとえば数値の足し算)を提供しているので、重複している部分があります。これらの機能の棲み分けが今後どうなってくるのかは。。。私もよくわかっていません。なんどか議論はされているのですが、結局どうなるのかピンときていませんし、現時点ではまだ目立った動きもありません。

参考:Compute kernels and Gandiva operators

Gandivaに関してはこの1年でそんなに目立った動きはない(使える関数は少しずつ増えていて開発は進んでいます)ので、動きがあった計算関数について説明します。

最近、計算関数の仕組みが書き直されました。これまでは静的に使う(コンパイル時にどの関数を使うか決める)方式だったのですが、動的に使う(実行時にどの関数を使うか決める)方式になりました。具体的にどう使い方が変わったかと言うと、実行時に名前で関数を探して、見つけた関数を実行するようになりました。名前は単なる文字列なので実行時に生成できます。

使い方が変わってどううれしいかピンとこないと思うので、ユーザー視点でうれしいこと例を示します。たとえば、PythonユーザーはC++実装に計算関数が増えたらPython実装を変えずに新しい計算関数を使えます。これまでは、C++実装に計算関数が増えたらPython実装にもその計算関数を使えるようにする処理が実装されないと使えませんでした。C++実装に「すごい計算関数」が追加されたらすぐにPythonスクリプトから「すごい計算関数」を使えるということです。

現時点では、C++実装とPython実装は同じタイミングでリリースされ、Python実装の漏れはほとんどありませんが、今後、C++実装にプラグインの仕組みができた場合はかなりうれしくなります。自分でC++で実装した計算関数をすぐにPythonスクリプトから使えるようになります。(伝わる?)

まだ計算関数をプラグインで追加できるようにするという話はあがっていませんが、別の機能をプラグインで拡張できるようにしない?という提案はあがっています。近い将来、プラグインの仕組みができるかもしれません。

計算関数もだいぶ増えました。複数カラムでのソートなど足りない機能はまだあるのですが、どんどん増えています。現在使える関数については計算関数のドキュメント(再掲)を参照してください。

計算関数の仕組みが書き直されたタイミングで計算関数を実装しやすくなっています。計算関数を実装したくなったらcpp/src/arrow/compute/の下をのぞいてください。

高速なデータ処理に関することだけでなく、高速なデータ交換に関することでも追加機能があったので説明します。

Cデータインターフェイス

Apache Arrowはネットワーク越し・プロセス越しなどいろいろなスケールでの高速なデータ交換を実現しようとしています。この1年でCデータインターフェイスという、同一プロセス内の別システム間でのデータ交換用のインターフェイスが増えました。

Apache Arrowを使うためには公式の実装を使うか自分たちが必要な分だけの自分たちの実装を作る必要があります。前述の通り、公式の実装はしばらく頻繁に互換性が壊れる想定なのでアップグレードに追従するコストが少なからず発生します。一方、独自に実装すると依存ライブラリーが増えなかったりアップグレードに追従するコストはありませんが、実装・メンテナンスはそれなりに大変です。(ちなみに、PG-StromのArrow_fdwは後者のアプローチです。)

Cデータインターフェイスを使うと、Apache Arrowの実装に依存せずに同一プロセス内の別システムとApache Arrowデータ(カラムナーデータ)を交換できます。ただし、単にデータを交換できるだけでApache Arrowフォーマットでの入出力や、Apache Arrowデータに対する高速なデータ処理機能はありません。たとえば、前述のArrow_fdwはApache Arrowフォーマットでの入出力があるのでCデータインターフェイスは使えません。

ユースケースの1つは、同一プロセス名で別言語が動いていてそれらの言語間でデータ交換したいケースです。たとえば、Introducing the Apache Arrow C Data Interface | Apache ArrowではRと同じプロセス内でPythonを動かし、RとPythonでデータをやり取りする例を紹介しています。(Cデータインターフェイス単体でではなく、Apache Arrowライブラリーと一緒に使用しています。)

私は、SQLite3がCデータインターフェイスでデータを提供するAPIを用意するとうれしいケースがあるのではないかと考えています。

CデータインターフェイスはCの構造体定義・関数定義・仕様だけを提供しています。この定義をコピーして、仕様に合わせて動くようにすればApache Arrowデータを交換できます。詳細はCデータインターフェイス(再掲)を参照してください。

この1年の大きな機能面での変更を説明したので、次はビルド関連・パッケージ関連について説明します。

C++実装のビルドオプション

Apache Arrowライブラリーはすぐに使える(batteries-included)開発プラットフォームを提供しようとしているため、たくさんの有用な機能が詰め込まれています。すべての機能を自前で実装しているわけではなく、すでに有用な実装がある場合はライブラリーとしてその機能を組み込んで提供します。そのため、フル機能のApache Arrowライブラリーには依存ライブラリーが多いです。

しかし、すべてのユースケースでフル機能のApache Arrowライブラリーが必要なわけではありません。そのため、C++実装では必要に応じて各機能をオン・オフできるようになっています。

もともと、デフォルトではほぼオンになっていたのですが、デフォルトでオフになりました。必要に応じてオンにするようになりました。1.0.0がリリースされたから久しぶりに自分でビルドしてみるか!という人はCMakeのオプションを再確認してください。

依存ライブラリーを動的にリンクするか静的にリンクするかも個別に選べるようになりました。(選べるようにする作業がそろそろ完了しそうです。)

また、静的にリンクしたApache Arrowライブラリーを簡単に使えるようになりました。(使えるようにする作業がそろそろ完了しそうです。)

静的にリンクしたApache Arrowライブラリーをリンクする場合は、Apache Arrowライブラリーにリンクするだけではなく、Apache Arrowライブラリーに静的にリンクしている依存ライブラリーも一緒にリンクする必要があります。これまではユーザーが依存ライブラリーを自分で追加しないといけなく、現実的には使えない状態だったのが、次の方法でユーザーが特になにもしなくても使えるようになりました。

Apache Arrowライブラリーにバンドルされている依存ライブラリーを使った場合:

  • バンドルされている依存ライブラリーをすべてまとめたlibarrow_bundled_dependencies.aを生成してインストール

  • Apache ArrowライブラリーのCMakeパッケージでは必要に応じてlibarrow_bundled_dependencies.aをリンクフラグに追加

    • pkg-configは未対応(これを書いていて対応するのを忘れていたことに気づいた)

システムの依存ライブラリーを使った場合:

  • Apache ArrowライブラリーのCMakeパッケージが必要に応じて依存ライブラリーの情報を集めてリンクフラグに追加(実装中)

    • pkg-configは未対応(↑の実装が終わったらやらないと)

このあたりの話や次に説明するパッケージ関連の話も書いてあるMaking Arrow C++ Builds Simpler, Smaller, and Faster | Apache Arrowも読んでみてください。

パッケージ関連

パッケージ関連もこの1年でさらによくなりました。

1年ほど前はPython用のwheelパッケージはもうメンテナンスできないよ…となっていたのですが、再び頑張ってメンテナンスするようになりました。メンテナンスを諦めていた理由は次の通りでした。

  • やる人がいない

  • 開発している人がやると時間がとられて開発が進まない

    • wheelのメンテナンスをするより開発を進める方が優先度が高い

wheelのメンテナンスのためにApache Arrowの開発に参加する人もいたのですが、なかなかタスクを完了するところまでいけませんでした。たとえば、Python 3.8対応のケースです。前述の通りApache Arrowライブラリーは依存関係が多く、すべての依存ライブラリーを同梱しないといけないwheelの作成は難しい(というか面倒)です。それに加えて、新しいバージョンのPythonに対応するのはまた難しい(というか面倒)だったのです。Python 3.8対応については私が引き取って完了させました。(どーん!)

Python 3.8対応の後は私も含めてコアの機能を作っている人たちがちまちま手を入れながらメンテナンスしています。

なお、wheelのメンテナンスに時間を割くようになったのはwheelユーザーが多かったからでした。(月間700万ダウンロードとかそういう感じ。)

1.0.0ではGandiva対応が削除されました。これはwheelのサイズを減らすためです。今後はpyarrowにすべてを入れるのではなくサブパッケージにわけて必要な人が必要な機能をインストールできるようにする予定です。wheelユーザーの人はこういう作業とかで一緒にメンテナンスしませんか?

Python実装ののwheel以外のパッケージもよくなっています。

Debian GNU/Linux、Ubuntu、CentOS、Amazon Linux用のパッケージはARM用のパッケージも提供するようになりました。(私も結構作業しました!)

MSYS2のパッケージではGandivaを使えるようになりました。Homebrewでも有効にしたかったのですが、libstdc++のリンクの問題があって有効にできませんでした。解決策はあるので次のリリースでは有効にできるといいな。MSYS2とHomebrewのパッケージでGandivaを有効にするために@naitohと私で最新のLLVMでもGandivaを使えるようにする作業を進めていました。1.0.0に間に合ってよかった。

R実装のパッケージもインストールしやすくなっています。R実装はC++実装のバインディングなのでC++実装が必要なのですが、ビルド済みのC++実装を使えるケースを増やしています。C++実装のビルド時に問題が発生することが多いので、これで問題が減るはずです。

インストールページの説明を更新できていないのですが、C#実装のパッケージが「オフィシャル」扱いになりました。Apache ArrowのPMCが投票して受理されたものが「オフィシャル」扱いなのですが、これまではC#実装のソースだけが「オフィシャル」扱いでビルド済みのパッケージは「アンオフィシャル」扱い(投票されていない)でした。

次の1年でRuby実装のパッケージも「オフィシャル」扱いにしたいな。

まとめ

2020年7月時点のApache Arrowの最新情報を、2019年9月からの差分という形でまとめました。Apache Arrowは1.0.0がついにリリースされたことが大きなニュースでした。1.0.0リリースによってデータ処理界隈で重要なコンポーネントになることでしょう。日本でもApache Arrowのことを知っている人が増えるといいと思うので日本語でまとめました。Apache Arrowを使う人が増えるといいなぁと思います。さらに言えば開発に参加する人も増えるといいなぁと思います。

私が知っていることはまとめたつもりですが、もしかしたらカバーできていない話があるかもしれません。もし、「○○についても知りたい!」という方がいたらApache Arrowのことを日本語で話せるチャットで声をかけてください。この記事に追加します。

Apache Arrowについて講演して欲しいという方はお問い合わせください。

私はデータ処理ツールの開発という仕事をしたいと思っています。その中にはもちろんApache Arrowの開発も含まれています。一緒に仕事をしたい!(自社サービスをApache Arrow対応したいとか)という方はお問い合わせください。