モチベーション

顧客からサンプルデータとして巨大な CSV を渡された時、それを処理するために BigQuery や PostgreSQL などの適当なデータベース(DBMS)にデータを投入したい場合があります。しかし DBMS はソフトウェアごとの方言が強く、それぞれの書き方にしたがってデータの投入を行うのは面倒です。

本記事では、 DBMS によらず、ほぼ同じ書き方で CSV からデータを投入する方法を示します。あくまで分析用のサンプルデータの受領という位置付けから、本番と同一のデータ型の再現は目指しません。簡単に分析のためのテーブル作成を考えます。

なお、本記事でいう DBMS とは、 DBMS のみではなくその関連技術(インターフェイスなど)を含みます。

方法

DBI パッケージによるテーブル作成

R には DBI パッケージという、 DBMS の操作を共通化するインターフェイスを提供するパッケージが存在します。このパッケージのおかげで、適切なコネクションを作成すれば、あとは同じ記述方法で様々な DBMS に対応した処理を行うことができます。

DBI パッケージに対応した代表的な DBMS とパッケージは下記の通りです。

DBMS パッケージ 備考
ODBC odbc SQL Server の例
JDBC RJDBC Treasure Data の例
Presto RPresto
BigQuery bigrquery
Athena AWR.Athena
PostgreSQL、 Redshift RPostgresRPostgreSQL
MySQL、 MariaDB RMySQLRMariaDB
SQLite RSQLite
Oracle ROracle

上記の通り ODBC、 JDBC に対応しているため、ほとんどの DBMS は網羅できると言っても過言ではないでしょう。

データフレーム df に対して、 DBI パッケージを利用したテーブルの作成は以下のように書くことができます。

library(DBI)

# DBMS に応じてコネクションを作成。ここでは SQLite を指定する。
con <- dbConnect(RSQLite::SQLite(), "mydb.sqlite3")
# データフレームを DBMS のテーブルに書き込む。
dbWriteTable(con, "table_name", df)

コネクション(上記コードの con オブジェクト)を DBMS に応じて適切に指定すれば、あとは全て dbWriteTable でテーブルの作成ができます。なお、すでにテーブルが存在する場合は、 dbWriteTable のパラメーター overwrite または appendTRUE を設定することで、上書きまたは追記が可能です。

readr パッケージによるチャンク処理

tidyverse メタパッケージにも含まれる readr パッケージのは、 CSV ファイルからデータフレームを作成することができます。 base パッケージの read.csv 関数を利用すると、 CSV すべてをメモリー上に読み込むため、 CSV のファイルが大きい場合はメモリー不足で実行することができません。このような場合は、 readr パッケージの read_csv_chunked 関数を利用します。

read_csv_chunked 関数は、 read_csv 関数(または read.csv 関数)と似ていますが、 chunked と名前のつく通り、すべてのレコードを一気に読み込むのではなく、指定したレコード数だけ読み込み、その読み込んだレコードの塊(チャンク)に対して逐次処理を行います。そのため、 callback という特別なパラメーターが存在し、ここにチャンクの処理を指定します。

CSV ファイルから少しずつデータフレームチャンクを読み込み、 DBI パッケージを利用してデータをテーブルに挿入するには以下のようにします。

library(readr)

callback <- function(df, pos) {
   dbWriteTable(con, "table_name", df, append = TRUE)
}
# デフォルトではチャンクサイズは 10,000 レコードずつ。
read_csv_chunked("sample.csv", DataFrameCallback$new(callback))

まとめ

R には DBI パッケージがあり、様々な DBMS に対応したテーブル作成操作が、共通の書き方で実行できます。また、 readr パッケージを利用することで、巨大な CSV ファイルであっても、少しずつデータを読み込んで処理することができます。