Apache ArrowのC++実装およびC++実装のCバインディング(Cで書かれたからC++実装を使うためのラッパー)のパッケージを公開しました。これにより簡単にApache Arrowを使えるようになります。C/C++だけでなく、Rubyからも簡単に使えるようになります。
なお、パッケージはApache Arrowプロジェクトが公式に提供しているものではなく、Apache Arrowプロジェクトの開発に参加している人が提供している非公式なものです。非公式なものですが、Apache Arrowについてもパッケージについてもよく知っている人が作っているものなので安心して利用できます。
対応プラットフォーム
以下のプラットフォーム用のパッケージを公開しました。
-
Debian GNU/Linux jessie
-
Ubuntu 16.04 LTS
-
Ubuntu 16.10
-
CentOS 7
それぞれのプラットフォームごとに利用方法を説明します。それぞれのセクションだけ(自分が使っているプラットフォームのセクションだけ)を読めば分かるように書いています。そのためそれぞれのセクションで重複した説明があります。
Debian GNU/Linux jessieとUbuntu 16.04 LTSとUbuntu 16.10
Debian GNU/Linux jessieとUbuntu 16.04 LTSとUbuntu 16.10でApache Arrowのパッケージを使う方法を説明します。最初のAPTリポジトリーを追加するところだけがDebian GNU/LinuxとUbuntuで違うだけでそれ以降は同じです。
まずApache Arrowのパッケージを提供しているAPTリポジトリー用のapt-lineを追加します。GroongaのAPTリポジトリーに相乗りしているので以下のapt-lineになります。
Debian GNU/Linux jessieの場合は、まず以下の内容の/etc/apt/sources.list.d/groonga.list
を作成してapt-lineを追加します。
deb http://packages.groonga.org/debian/ jessie main
deb-src http://packages.groonga.org/debian/ jessie main
次にこのapt-lineで追加したAPTリポジトリーを使えるようにします。
% sudo apt update
% sudo apt install -y --allow-unauthenticated groonga-keyring
% sudo apt update
Ubuntuの場合は次のようにします。
% sudo apt install -y software-properties-common
% sudo add-apt-repository -y ppa:groonga/ppa
% sudo apt update
これでパッケージをインストールする準備ができました。以下はDebian GNU/Linux jessie、Ubuntu 16.04 LTS、Ubuntu 16.10で共通です。
Apache ArrowのC++実装を使う場合はlibarrow-dev
パッケージをインストールします。
% sudo apt install -y libarrow-dev
Cバインディングを使う場合はlibarrow-glib-dev
パッケージをインストールします。Cバインディングを使うと、Ruby、Lua、Go、Rustなどからも使えるようになります。Ruby、Lua、Go、Rustなどから使いたい場合はlibarrow-glib-dev
パッケージをインストールしてください。
% sudo apt install -y libarrow-glib-dev
RubyでApache Arrowを使う場合は、まずはRubyをインストールします。拡張ライブラリーを使うのでruby-dev
パッケージもインストールします。
% sudo apt install -y ruby ruby-dev
red-arrow gemをインストールするとRubyからApache Arrowを使えるようになります。
% sudo gem install red-arrow
以下はRubyの配列とApache Arrowの配列を変換する例です。
require "arrow"
counts = Arrow::UInt32Array.new([1, 2, 4, 8])
p counts.to_a # => [1, 2, 4, 8]
以下は↑と同じ内容の配列を2回にわけて/tmp/logs-stream.arrow
に書き出す例です。Apache Arrowは効率のよいプロセス間のデータ交換の実現も大事にしているので、データの書き出しはよくある使い方です。
#!/usr/bin/env ruby
require "arrow"
fields = [
Arrow::Field.new("count", Arrow::UInt32DataType.new),
]
schema = Arrow::Schema.new(fields)
Arrow::IO::FileOutputStream.open("/tmp/logs-stream.arrow", false) do |output|
Arrow::IPC::StreamWriter.open(output, schema) do |writer|
counts1 = [1, 2]
arrow_counts1 = Arrow::UInt32Array.new(counts1)
record_batch = Arrow::RecordBatch.new(schema, counts1.size, [arrow_counts1])
writer.write_record_batch(record_batch)
counts2 = [4, 8]
arrow_counts2 = Arrow::UInt32Array.new(counts2)
record_batch = Arrow::RecordBatch.new(schema, counts2.size, [arrow_counts2])
writer.write_record_batch(record_batch)
end
end
それでは、このデータをLuaから読み出してみましょう。LuaからApache Arrowを使うにはLGIを使います。
% sudo apt install -y luarocks
% sudo luarocks install lgi
以下のコードでRubyで書き出したデータを読み込めます。MemoryMappedFile
というオブジェクトを使って読み込んでいるのでゼロコピー(コピーなし)でデータを読み込んでいるので効率的です。
local lgi = require 'lgi'
local Arrow = lgi.Arrow
local ArrowIO = lgi.ArrowIO
local ArrowIPC = lgi.ArrowIPC
local input = ArrowIO.MemoryMappedFile.open("/tmp/logs-stream.arrow", ArrowIO.FileMode.READ)
local reader = ArrowIPC.StreamReader.open(input)
local i = 0
while true do
local record_batch = reader:get_next_record_batch()
if not record_batch then
break
end
local column = record_batch:get_column(0)
for j = 0, record_batch:get_n_rows() - 1 do
print("record_batch["..i.."]["..j.."] = " .. column:get_value(j))
-- record_batch[0][0] = 1
-- record_batch[0][1] = 2
-- record_batch[1][0] = 4
-- record_batch[1][1] = 8
end
i = i + 1
end
input:close()
実行すると次のように表示されます。きちんと読み込めていますね。
record_batch[0][0] = 1
record_batch[0][1] = 2
record_batch[1][0] = 4
record_batch[1][1] = 8
次はPythonのPandasで作ったデータを書き出してRubyから読み込んでみましょう。
PythonからApache Arrowを使うにはpyarrowをインストールします。
% wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
% bash Miniconda3-latest-Linux-x86_64.sh
% source ~/.bashrc
% conda install -y --channel conda-forge pyarrow
Pandasで作ったデータをApache ArrowのRecordBatch
に変換してファイルに書き出します。
#!/usr/bin/env python
import pandas as pd
import numpy as np
import pyarrow as arrow
df = pd.DataFrame({'count': [1, 2, 4, 8]})
batch = arrow.RecordBatch.from_pandas(df)
sink = arrow.io.OSFile("/tmp/logs.arrow", "w")
writer = arrow.ipc.FileWriter(sink, batch.schema)
writer.write_batch(batch)
writer.close()
sink.close()
このデータを読み込むRubyのコードは次の通りです。
#!/usr/bin/env ruby
require "arrow"
Arrow::IO::MemoryMappedFile.open("/tmp/logs.arrow", :read) do |input|
Arrow::IPC::FileReader.open(input) do |reader|
reader.each do |record_batch|
record_batch.each do |record|
p record[:count]
# 1
# 2
# 4
# 8
end
end
end
end
次のように出力されるので正しく読み込めています。
1
2
4
8
CentOS 7
CentOS 7でApache Arrowのパッケージを使う方法を説明します。
まずApache Arrowのパッケージを提供しているYumリポジトリーを追加します。GroongaのYumリポジトリーに相乗りしているので以下のように追加します。
% sudo yum install -y http://packages.groonga.org/centos/groonga-release-1.2.0-1.noarch.rpm
これでパッケージをインストールする準備ができました。
Apache ArrowのC++実装を使う場合はarrow-devel
パッケージをインストールします。
% sudo yum install -y arrow-devel
Cバインディングを使う場合はarrow-glib-devel
パッケージをインストールします。Cバインディングを使うと、Ruby、Lua、Go、Rustなどからも使えるようになります。Ruby、Lua、Go、Rustなどから使いたい場合はarrow-glib-devel
パッケージをインストールしてください。
% sudo yum install -y arrow-glib-devel
RubyでApache Arrowを使う場合は、まずはRubyをインストールします。
% sudo yum install -y git gcc openssl-devel readline-devel zlib-devel
% git clone https://github.com/rbenv/rbenv.git ~/.rbenv
% echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
% echo 'eval "$(~/.rbenv/bin/rbenv init)"' >> ~/.bash_profile
% source ~/.bash_profile
% git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
% rbenv install 2.4.1
red-arrow gemをインストールするとRubyからApache Arrowを使えるようになります。
% gem install red-arrow
以下はRubyの配列とApache Arrowの配列を変換する例です。
require "arrow"
counts = Arrow::UInt32Array.new([1, 2, 4, 8])
p counts.to_a # => [1, 2, 4, 8]
以下は↑と同じ内容の配列を2回にわけて/tmp/logs-stream.arrow
に書き出す例です。Apache Arrowは効率のよいプロセス間のデータ交換の実現も大事にしているので、データの書き出しはよくある使い方です。
#!/usr/bin/env ruby
require "arrow"
fields = [
Arrow::Field.new("count", Arrow::UInt32DataType.new),
]
schema = Arrow::Schema.new(fields)
Arrow::IO::FileOutputStream.open("/tmp/logs-stream.arrow", false) do |output|
Arrow::IPC::StreamWriter.open(output, schema) do |writer|
counts1 = [1, 2]
arrow_counts1 = Arrow::UInt32Array.new(counts1)
record_batch = Arrow::RecordBatch.new(schema, counts1.size, [arrow_counts1])
writer.write_record_batch(record_batch)
counts2 = [4, 8]
arrow_counts2 = Arrow::UInt32Array.new(counts2)
record_batch = Arrow::RecordBatch.new(schema, counts2.size, [arrow_counts2])
writer.write_record_batch(record_batch)
end
end
それでは、このデータをLuaから読み出してみましょう。LuaからApache Arrowを使うにはLGIを使います。
% sudo yum install -y lua-devel luarocks gobject-introspection-devel
% sudo luarocks install lgi
以下のコードでRubyで書き出したデータを読み込めます。MemoryMappedFile
というオブジェクトを使って読み込んでいるのでゼロコピー(コピーなし)でデータを読み込んでいるので効率的です。
local lgi = require 'lgi'
local Arrow = lgi.Arrow
local ArrowIO = lgi.ArrowIO
local ArrowIPC = lgi.ArrowIPC
local input = ArrowIO.MemoryMappedFile.open("/tmp/logs-stream.arrow", ArrowIO.FileMode.READ)
local reader = ArrowIPC.StreamReader.open(input)
local i = 0
while true do
local record_batch = reader:get_next_record_batch()
if not record_batch then
break
end
local column = record_batch:get_column(0)
for j = 0, record_batch:get_n_rows() - 1 do
print("record_batch["..i.."]["..j.."] = " .. column:get_value(j))
-- record_batch[0][0] = 1
-- record_batch[0][1] = 2
-- record_batch[1][0] = 4
-- record_batch[1][1] = 8
end
i = i + 1
end
input:close()
実行すると次のように表示されます。きちんと読み込めていますね。
record_batch[0][0] = 1
record_batch[0][1] = 2
record_batch[1][0] = 4
record_batch[1][1] = 8
次はPythonのPandasで作ったデータを書き出してRubyから読み込んでみましょう。
PythonからApache Arrowを使うにはpyarrowをインストールします。
% wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
% bash Miniconda3-latest-Linux-x86_64.sh
% source ~/.bashrc
% conda install -y --channel conda-forge pyarrow
Pandasで作ったデータをApache ArrowのRecordBatch
に変換してファイルに書き出します。
#!/usr/bin/env python
import pandas as pd
import numpy as np
import pyarrow as arrow
df = pd.DataFrame({'count': [1, 2, 4, 8]})
batch = arrow.RecordBatch.from_pandas(df)
sink = arrow.io.OSFile("/tmp/logs.arrow", "w")
writer = arrow.ipc.FileWriter(sink, batch.schema)
writer.write_batch(batch)
writer.close()
sink.close()
このデータを読み込むRubyのコードは次の通りです。
#!/usr/bin/env ruby
require "arrow"
Arrow::IO::MemoryMappedFile.open("/tmp/logs.arrow", :read) do |input|
Arrow::IPC::FileReader.open(input) do |reader|
reader.each do |record_batch|
record_batch.each do |record|
p record[:count]
# 1
# 2
# 4
# 8
end
end
end
end
次のように出力されるので正しく読み込めています。
1
2
4
8
まとめ
Apache ArrowをC/C++/Ruby/Lua/Go/Rustなどから使いやすくするためにApache ArrowのC++実装とそのCバインディングのパッケージを公開しました。
Apache Arrowを使っていろんな言語をデータ分析に活用してください。