R meets MongoDB


最近、割と大きめなデータをRで扱う際に、どのようなソリューションがいいか色々と考えています。
ここでのソリューションは並列計算云々という観点ではなく、大きめのデータから必要なデータをさっくりと用意して、解析フェーズに簡単に入っていくために、という観点です。

1つは有名すぎるbigmemoryというソリューションがあって、これは今後浸透していくんだろうなぁとは思いつつ、bigmemoryではデータ型がbig.matrixという特殊なものになってしまうので、既存のMatrixやdata.frameを使ったパッケージの関数が使えなくなってしまう*1という点が微妙だなぁと思っています。

そんな時に、Twitterのtimellineを眺めていたら、MongoDBのR driverができたとかいうtweetを見かけました。
MongoDBはかなり柔軟に色々できますし、何より今アツいトピックの1つですので、試すっきゃないですよね。

結論から言うと、かなり簡単に環境を作れる上に、色々と柔軟に解析基盤を構築できそうでいい感じだなぁと思っています。

MongoDBのインストール

MongoDBはドキュメントがしっかりしていますので、環境に合わせて
Downloads - MongoDB
http://www.mongodb.org/display/DOCS/Quickstart
を見ながら進めれば非常に簡単です。今回の本題ではないので割愛

rmongodbのインストール

github上にコードが上がっていますのでとってきます。 

$ cd /path/to/local/git/repository/
$ git clone https://github.com/gerald-lindsly/rmongodb.git

ここでテンションが上がってしまい、

$ R CMD install rmongodb

としてもエラーがでます。bson.hがないとか、そんな感じで怒られます。

心を鎮めてドキュメントを読みましょう。
README.mdにインストール手順が書いてありますので、それに従います。

After cloning the repo, drop mongo-c-driver's src directory into rmongodb/rmongodb/src

なので、
mongo-c-driver/src at master · mongodb/mongo-c-driver · GitHubからmongo-c-driverを落として来ます。

$ cd /path/to/local/git/repository/
$ git clone https://github.com/mongodb/mongo-c-driver/tree/master/src

次に落として来たソースコードrmongodbのディレクトリに突っ込みます。
ここで一点落とし穴があります。
mongo-c-driverのsrc"ディレクトリ"をrmongodb/romongodb/srcに突っ込め、と書いてありますが、実際はmongo-c-driverのsrcディレクトリ"以下のファイル一式"をrmonogodb/rmonogodb/srcに突っ込みます。
src以下にsrcディレクトリできるとかきたねーと思っていましたが、やっぱり違いました。
それとも英語の誤読ですかね?

ソースコードを所定の場所に置いた後、

$ R CMD install rmongodb

これで、うまくインストールされました。
パチパチー

rmongodbを使ってみる

まずはおもむろにMongoDBを起動します。

$ /path/to/monogo-bin/mongod

この状態でRを起動します。

$ R
> library(rmongodb)

おー、rmonogodbが無事に読み込まれます。
この後どうすればよいかわからないので、おもむろに

help(monogo)

と叩くと、例が表示されます。

mongo <- mongo.create()
if (mongo.is.connected(mongo)) {
    buf <- mongo.bson.buffer.create()
    mongo.bson.buffer.append(buf, "name", "Joe")     
    mongo.bson.buffer.append(buf, "age", 22L)
    b <- mongo.bson.from.buffer(buf)
    mongo.insert(mongo, "test.people", b)
}

これはMongoDBへデータの挿入を行っています。

  1. mongodbへ接続して(mongo.create())
  2. 接続がうまくいっていれば(mongo.is.connected(monogo))
  3. bson用のバッファーを作成(monogo.bson.buffer.create())
  4. bufferに{"name" : "Joe"}を追加(mongo.bson.buffer.append(buf, "name", "Joe"))
  5. 同様に{"age" : 22L}を追加
  6. bufferをbson形式に変換(mongo.bson.from.buffer(buf))
  7. db:test, collection:peopleにデータをinsert(mongo.insert(mongo, "test.people", b))

上でできるレコードとしては、{"name" : "Joe", "age" : 22L}ですね。

データを取得するときは

mongo <- mongo.create()
if (mongo.is.connected(mongo)) {
    buf <- mongo.bson.buffer.create()
    mongo.bson.buffer.append(buf, "name", "Joe")     
    mongo.bson.buffer.append(buf, "age", 22L)
    b <- mongo.bson.from.buffer(buf)
    mongo.insert(mongo, "test.people", b)
}

mongo.find()やmongo.find.one()を利用します。
同じく

help(mongo.find)
help(mongo.find.one)

で例が確認できます。

mongo.find.one()を使って、先ほどinsertしたデータを取得してみます。

mongo <- mongo.create()
if (mongo.is.connected(mongo)) {
    buf <- mongo.bson.buffer.create()
    mongo.bson.buffer.append(buf, "name", "Joe")     
    query <- mongo.bson.from.buffer(buf)
    
    mongo.find.one(mongo, "test.people", query))
}

とすると

> mongo.find.one(mongo, "test.people", query)
        _id : 7          4e60f5382607c787a9ccc2b6
        name : 2         Joe
        age : 16         22

こんな感じでデータが取得できます。

所感

MongoDBは個人的に注目のトピックでけっこう気になっていたのですが、なかなか触る機会が作れていませんでした。
Rは非常に便利な言語なのですが、データ量が大きくなってきたときに、既に出力されているデータファイルを読み込んで任意のレコードを取得・結合・・・みたいなことをするのがちょっとめんどくさいなぁという感じでしたので、mongodbを気軽に使えるというのは非常にいい感じだと思いました。

また、インストール手順(Cのドライバを全部突っ込む)や、rmongodbのドキュメントを読んでいると、どうやらCのAPIをRから叩くようになっているため、非常に多くの関数が提供されています。
MongoDB自体を簡単に操作できるために、非常に柔軟にいろいろな事ができるような気がしました。

こういう感じでRから気軽にNoSQLが扱えるのは今後非常に有益だなーと思います。
MongoDBを使ってるサービスも増えて来てますしね!

追記

buf <- mongo.bson.buffer.create()
mongo.bson.buffer.append(buf, "name", "Joe")     
query <- mongo.bson.from.buffer(buf)
mongo.find.one(mongo, "test.people", query))

こういう書き方、冗長だしなんか気持悪いなぁと思っていたらリストを使って以下のように書けるみたいです。

mongo.find.one(mongo, "test.people", list(name="Joe"))

これならすっきりして非常にいい感じ!!

*1:[:]でmatrixに変換できますがそれは本末転倒だと思いますし・・・