モチベーション
顧客からサンプルデータとして巨大な 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 | RPostgres、 RPostgreSQL | |
MySQL、 MariaDB | RMySQL、 RMariaDB | |
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
または append
に TRUE
を設定することで、上書きまたは追記が可能です。
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 ファイルであっても、少しずつデータを読み込んで処理することができます。