ククログ

株式会社クリアコード > ククログ > Apache Arrowの(非公式)パッケージを公開

Apache Arrowの(非公式)パッケージを公開

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を使っていろんな言語をデータ分析に活用してください。