0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RubyでApache Arrow/Parquetを試してみた ~Red Arrow/Red Parquet入門~

Last updated at Posted at 2025-12-22

RubyでApache Arrow/Parquetを試してみた ~Red Arrow/Red Parquet入門~

はじめに

「Apache Arrow/Parquetって何がすごいの?」をRubyで体感したくて試してみました。
この記事では、Arrow/Parquetの概要と、Rubyでの使い方(Red Arrow/Red Parquet)を紹介します。

Arrow/Parquetとは?

Apache Arrow

  • インメモリ・フォーマット(列指向)
  • 異なる言語間で高速にデータをやり取りできる
  • 公式: arrow.apache.org

Apache Parquet

  • ストレージ・フォーマット(列指向ファイル形式)
  • データ保存・取得が効率的
  • 公式: parquet.apache.org

Red Arrow(Ruby用Arrow Gem)

Red Parquet(Ruby用Parquet Gem)

ざっくりまとめ

  • Arrow: メモリ上の共通語(高速処理・言語間連携)
  • Parquet: ディスク保存の効率化(I/O最適化)
  • Red Arrow: RubyでArrowフォーマットのデータ構造(Arrow::Tableなど)を高速に扱えるGem
  • Red Parquet: RubyでParquetファイルの読み書きができるGem(Arrowデータとの連携も簡単)

試す

ディレクトリ構成
redarrow/
├── Dockerfile
├── generate_file.rb
├── read_csv_with_redarrow.rb
├── read_csv_with_std.rb

Dockerfile
# 最新の安定版Rubyイメージを使用
FROM ruby:latest

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    wget \
    ca-certificates \
    lsb-release \
    build-essential \
    pkg-config \
    libglib2.0-dev \
    libgirepository1.0-dev \
    && rm -rf /var/lib/apt/lists/*

RUN wget -q -O /tmp/apache-arrow-apt-source.deb https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb && \
    apt-get install -y --no-install-recommends /tmp/apache-arrow-apt-source.deb && \
    rm /tmp/apache-arrow-apt-source.deb && \
    apt-get update && \
    apt-get install -y --no-install-recommends \
        libarrow-glib-dev \
        libparquet-glib-dev \
    && rm -rf /var/lib/apt/lists/*

RUN gem install rubygems-requirements-system --no-document

RUN gem install red-arrow red-parquet --no-document

# 作業ディレクトリの設定
WORKDIR /usr/src/app

CMD ["/bin/bash"]
generate_file.rb
require 'pathname'
require 'fileutils'

CSV_FILE = "large_sample_data.csv"
PARQUET_FILE = CSV_FILE.sub(".csv", ".parquet")
NUM_RECORDS = 10_000_000

def generate_large_csv(file_path, num_records)
  puts "--- CSVファイル生成開始 (#{num_records}行) ---"
  
  start_time = Time.now
  
  header = "id,value,category\n"
  
  data = num_records.times.map do |i|
    id = i + 1
    value = (Math.sin(i / 100.0) * 1000).round(2)
    category = "GROUP_#{i % 5}"
    "#{id},#{value},#{category}\n"
  end
  
  File.write(file_path, header + data.join)
  
  duration = (Time.now - start_time).round(3)
  
  csv_size_mb = File.size(file_path) / (1024.0**2)
  puts "CSVファイル生成完了。"
  puts "  所要時間: #{duration}秒"
  puts "  ファイルサイズ: #{csv_size_mb.round(2)} MB"
end

[CSV_FILE, PARQUET_FILE].each do |f|
  if File.exist?(f)
    File.delete(f)
    puts "既存ファイルを削除しました: #{f}"
  end
end

begin
  generate_large_csv(CSV_FILE, NUM_RECORDS)
  puts "\nデータ生成処理完了。読み込み時間計測には、他のスクリプトを実行してください。"
rescue => e
  puts "\nエラーが発生しました: #{e.class} - #{e.message}"
end
read_csv_with_redarrow.rb
require 'arrow'
require 'parquet'
require 'pathname'
require 'fileutils'

CSV_FILE = "large_sample_data.csv"
PARQUET_FILE = CSV_FILE.sub(".csv", ".parquet")
NUM_RECORDS = 10_000_000

def process_data_with_redarrow(csv_file, parquet_file)
  unless File.exist?(csv_file)
    puts "エラー: データファイルが見つかりません: #{csv_file}"
    return
  end
  
  puts "\n--- Apache Arrow/Parquet 処理開始 ---"
  
  if File.exist?(parquet_file)
    File.delete(parquet_file)
    puts "既存Parquetファイルを削除しました: #{parquet_file}"
  end
  
  # 1. CSV -> Arrow Table 読み込み
  puts "フェーズ 1: CSV -> Arrow Table ロード開始"
  csv_read_start_time = Time.now
  table = Arrow::Table.load(csv_file)
  csv_read_duration = (Time.now - csv_read_start_time).round(3)
  puts "CSVロード完了。所要時間: #{csv_read_duration}秒"
  
  # 2. Arrow Table -> Parquetへの書き出し
  puts "フェーズ 2: Arrow Table -> Parquet ファイル書き出し開始"
  parquet_write_start_time = Time.now
  table.save(parquet_file, format: :parquet)
  parquet_write_duration = (Time.now - parquet_write_start_time).round(3)
  puts "Parquet書き出し完了。所要時間: #{parquet_write_duration}秒"

  # 3. Parquetの読み込み
  puts "フェーズ 3: Parquet ファイル -> Arrow Table ロード開始"
  parquet_read_start_time = Time.now
  parquet_table = Arrow::Table.load(parquet_file) 
  parquet_read_duration = (Time.now - parquet_read_start_time).round(3)
  puts "Parquetロード完了。所要時間: #{parquet_read_duration}秒"
  
  # ファイルサイズ計測
  csv_size_mb = File.size(csv_file) / (1024.0**2)
  parquet_size_mb = File.size(parquet_file) / (1024.0**2)
  
  # 計測結果の比較表示
  puts "\n--- 処理結果サマリー ---"
  puts "処理時間:"
  puts "  CSV読み込み時間: #{csv_read_duration}秒"
  puts "  Parquet書き出し時間: #{parquet_write_duration}秒"
  puts "  Parquet読み込み時間: #{parquet_read_duration}秒"

  puts "\nファイルサイズ:"
  puts "  CSVファイルサイズ: #{csv_size_mb.round(2)} MB"
  puts "  Parquetファイルサイズ: #{parquet_size_mb.round(2)} MB"
end

begin
  process_data_with_redarrow(CSV_FILE, PARQUET_FILE)
  puts "\n処理を終了します。"
rescue => e
  puts "\nエラーが発生しました: #{e.class} - #{e.message}"
end
read_csv_with_std.rb
require 'csv'
require 'pathname'
require 'fileutils'

CSV_FILE = "large_sample_data.csv"

def read_csv_read_io_only(csv_file)
  unless File.exist?(csv_file)
    puts "エラー: データファイルが見つかりません: #{csv_file}"
    return
  end
  
  puts "\n--- CSVファイルの読み込み開始 ---"
  puts "注意: ファイル全体がメモリにロードされます。"
  
  read_start_time = Time.now
  
  csv_table = CSV.read(csv_file, headers: true) 
  
  load_duration = (Time.now - read_start_time).round(3)
  
  record_count = csv_table.size
  
  puts "CSVデータ読み込み完了。"
  puts "  所要時間: #{load_duration}秒"
  puts "  レコード数: #{record_count}"
  
  return load_duration
end

begin
  read_csv_read_io_only(CSV_FILE)
  puts "\n処理を終了します。"
rescue => e
  puts "\nエラーが発生しました: #{e.class} - #{e.message}"
end

docker imageつくって中に入る

docker build --no-cache -t red-arrow-test . 
docker run --rm -it -v "$(pwd)":/usr/src/app red-arrow-test /bin/bash

1000万行の4列のcsvデータつくる

ruby generate_file.rb

rubyの標準のCSV.readをつかって作成したファイル読み込んでみる

ruby read_csv_with_std.rb

Red ArrowをつかってCSVファイルを読み込んだり、パーケット出力してみたりする

ruby read_csv_with_redarrow.rb

ベンチマーク結果 

とても単純なデータ生成しかしていないので、不正確だとはおもいますが、下記な感じ

データ生成

  • 1,000万行のCSVファイルを生成
  • 所要時間: 7.774秒
  • ファイルサイズ: 221.44 MB

標準CSV(Ruby標準CSVライブラリ)

  • 読み込み時間: 42.086秒
  • レコード数: 10,000,000

Red Arrow/Red Parquet

  • CSV → Arrow Table 読み込み: 0.672秒
  • Arrow Table → Parquet書き出し: 0.695秒
  • Parquet → Arrow Table 読み込み: 0.433秒
  • Parquetファイルサイズ: 158.05 MB

サマリー

処理内容 標準CSV Red Arrow/Parquet
CSV読み込み 42.086秒 0.672秒
Parquet書き出し - 0.695秒
Parquet読み込み - 0.433秒
CSVファイルサイズ 221.44MB 221.44MB
Parquetファイルサイズ - 158.05MB

所感

  • Red Arrow/Parquetは圧倒的に高速(CSV読み込みで約60倍速い)
  • Parquetはファイルサイズも小さく、I/O効率も良い
  • 大量データ処理や分析用途では、Arrow/Parquet+Red Arrow/Red Parquetの組み合わせが非常に有効

まとめ

今回はApache ArrowとApache ParquetをRubyから扱い、どれくらい高速に大量データを処理できるかをざっくり試してみました。
RubyのGem(Red Arrow/Red Parquet)を使うことで、標準CSVより圧倒的に速く・効率的にデータを読み込めることが分かりました。

実際にベンチマークしてみて、
「大量データでもストレスなく扱える」「ファイルサイズも小さくなる」など、
データ分析やETL処理の現場でも十分使える手応えを感じました。

次は、Arrow/Parquetで読み込んだデータを使って、
Rubyで可視化・機械学習などの実践を調査したいと思います。

参考情報・素晴らしいGemを公開してくださっている皆様に感謝します。
red-data-tools
ClearCodeさんのブログ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?