データ分析とかをしていると大規模データを扱うことがある。
複数のライブラリを使う際にデータ連携を行う際に一度CSVやJSONに出力して連携先ではそれをパースしてといった方法をとることがある。
数メガくらいのファイルであれば問題にはならないが、これがギガなどになってくるとこのデータ連携コストが無視できなくなってくる。
これを解決する方法の1つとしてApache Arrowというものがある。
今回はこれを紹介して実際にどれくらい早いのかを検証してみる。
Apache Arrowとは?
- 2016年の10月に0.1.0がリリース
- メモリ上でカラム型データを扱うためのフォーマットとアルゴリズム
カラム型でデータを格納するので効率よく圧縮することが出来、メモリ上に書き込むことで読み書きの速さを実現している。
昔はメモリなどのリソースは潤沢に使うことは用意ではなかったが、昨今ではAWSなどで何十Gものメモリを積んだマシンを使用することが出来るため、このようなものが生きてくる。
このApache ArrowはPython, RubyやC, C++などから扱うことが現状出来る。
実際に速さを体験してみる
検証について
今回はEC2のt2.largeを使って検証を行った
Ubuntu: 16.04.2 CPU: 2 メモリ: 8G Python: 3.6.2 Ruby: 2.4.1 Arrow: 0.6.0
今回はこれを使ってPythonでCSV、Arrowで2.3Gのデータを出力しRubyでそれぞれを読み込んだ時の速度を見る。
CSV
Pythonでの書き込み
import pandas as pd import pyarrow as pa from time import time df = pd.DataFrame({"a": ["a" * i for i in list(range(40000))], "b": ["b" * i for i in list(range(40000))], "c": ["c" * i for i in list(range(40000))]}) start_time = time() df.to_csv("test.csv", header=False) print("write : {0}s".format(time() - start_time))
Rubyでの読み込み
require "time" require "csv" start_time = Time.now CSV.open("test.csv", headers: false) do |row| puts "batch size : #{row.count}" end puts "read : #{Time.now - start_time}s"
Apache Arrow
Pythonでの書き込み
#-*- using:utf-8 -*- import pandas as pd import pyarrow as pa from time import time df = pd.DataFrame({"a": ["a" * i for i in list(range(40000))], "b": ["b" * i for i in list(range(40000))], "c": ["c" * i for i in list(range(40000))]}) start_time = time() record_batch = pa.RecordBatch.from_pandas(df) with pa.OSFile("/dev/shm/pandas.arrow", "wb") as sink: schema = record_batch.schema writer = pa.RecordBatchFileWriter(sink, schema) writer.write_batch(record_batch) writer.close() print("write : {0}s".format(time() - start_time))
Rubyでの読み込み
require "arrow" require "time" require "csv" Input = Arrow::MemoryMappedInputStream start_time = Time.now Input.open("/dev/shm/pandas.arrow") do |input| reader = Arrow::RecordBatchFileReader.new(input) puts "batch size : #{reader.get_record_batch(0).count}" end puts "read : #{Time.now - start_time}s"
検証
CSVの時
Write (s) | Read (s) | |
---|---|---|
1 | 51.62104869 | 4.85522798 |
2 | 51.43777633 | 4.864032677 |
3 | 51.35622239 | 4.885216672 |
4 | 51.46343231 | 4.865155221 |
5 | 51.39711213 | 4.870614692 |
Apache Arrowの時
Write (s) | Read (s) | |
---|---|---|
1 | 3.39462328 | 0.013111846 |
2 | 3.312984943 | 0.013321837 |
3 | 3.332154036 | 0.013229807 |
4 | 3.342362165 | 0.013370328 |
5 | 3.306367636 | 0.012740001 |
それぞれの場合で5回ほど実行して平均をとると
CSVの時が書き込みに51.46秒、読み込みに4.87秒
Apache Arrowの時が書き込みに3.34秒、読み込みに0.01秒
書き込みも読み込みも早くなってますね!!