CouchDBをちょっとだけいじってみた(修正あり)

このプレゼン資料にw感動wして使ってみたくなった。

(検索でいらした方向け追記:ここの記事より、以下のシリーズ記事がとても参考になると思います。

  1. Web 時代の非リレーショナルデータベース: 第 1 回 Apache CouchDB の概要とインストール
  2. Web 時代の非リレーショナルデータベース: 第 2 回 Apache CouchDB と Ruby on Rails を使って wiki アプリケーションを作成する
  3. Web 時代の非リレーショナルデータベース: 第 3 回 Apache CouchDB で MapReduce フレームワークに基づく問いあわせを行う
  4. Web 時代の非リレーショナルデータベース: 第 4 回 Apache CouchDB の便利な機能を習得する
  5. Web 時代の非リレーショナルデータベース: 第 5 回 Apache CouchDB の最新機能を知り、適用の勘所を掴む

追記終わり)
(2009/10/29追記:リクエストのAPIをまとめたものをWikiで見つけました。
HTTP_view_API - Couchdb Wiki 追記終わり)
(2009/11/09追記:google groupのcouchdb-jpで、Web上で公開されているCouchDB本のdraftの翻訳プロジェクトが進んでいるようです。以下を見ると結構できてますねー。素晴らしい。
 追記終わり)

もともとApacheのIncubator(Google Labみたいなもんか)プロジェクト。
Ruby on Railsを初体験したときは、WebサービスのアーキテクチャRDBMS(要するにMySQLだけど)のインピーダンスマッチングをとることと、サービスの宣言的設計を可能にするDSL+Ajaxライブラリが強烈に印象に残ったけれど、CouchDBはそのうちのRDBMSとのマッチングの部分をDBの側で吸収した形になっていると思う*1。こうなると、CouchDBRailsのDSLの部分を組み合わせるというやり方もあるはず。Rackを使ってなんとかなるんだろうか、というのが次の興味。(DSLの話としては、最近読んでいるThoghtWorksアンソロジーの第2章がおもしろかった)

  • 行と列のテーブルを格納するRelational DBとは異なって、JSONのドキュメントをそのまま格納する。
  • queryはmap(演算・選択)-Reduce(整列)の手続きをあたえてviewを定義することで行う
  • replicationの機能がbuilt-inされていて、各ドキュメント単位(UUID付き)でrevision controlされている
  • アクセスはRESTfulに実行する。HTTPで直接叩けるAPIなので、事実上言語bindingは不要。コマンドラインからcurlを使ったり、ブラウザからアクセスすることもできる。mochiWebが統合されていて、GUIのインターフェースもある。
  • 並列分散処理可能である
    • 並列分散処理されるDBの一貫性や完全性やスケーラビリティのトレードオフはどうなっているかを一言で言えばEventual Consistencyであるらしい(あとで読む)

ガイドブックとしては、今後O'Reillyから発売予定のCouchDB: The Definitive Guideがいいだろう。このサポートサイトには入門的な部分のテキストが掲載されているので、ちょっと使ってみるにはこれで十分。

インストール

参照:Installation - Couchdb Wiki
例えばRedhat系ならば以下のような感じ。

# yum install ncurses-devel openssl-devel icu libicu-devel js js-devel curl-devel erlang
# svn checkout http://svn.apache.org/repos/asf/couchdb/trunk couchdb
# cd couchdb
# ./bootstrap
# ./configure --with-erlang=/usr/(local/)lib(64)/erlang/usr/include && make && make install

インストールできたら、/usr/local/bin/couchdb を実行すればサーバが立ち上がる。デフォルトのポートはtcpで5984。iptablesなどでアクセスできるIPなどを制限しておくことをお薦めする。
設定を変えたければ /usr/local/etc/couchdb/local.iniを編集うする。

コマンドラインからAPIへアクセスしてみる

ここからはGetting StartedThe Core APIからの「写経」なので、英語が多少なりとも読めるなら、原文に当たるが吉。わかりにくかったら、その旨要望を出せば、著者たちから感謝されるかもしれない(笑
HTTPのリクエスト出すならcurlが使える。-vのオプションをつけるとリクエストヘッダやレスポンスヘッダも取れるので、最初のうちは重宝する。HTTP/1.1使ってるんだね、とか。わかる。
サーバ生きてますか?
ルートのURIを叩くとサーバの情報が取れる。

# curl http://127.0.0.1:5984/
{"couchdb":"Welcome","version":"0.10.0a800717"}

show databasesに相当するパスは /_all_dbs だ。アンダースコアで始まるパスにはシステム上特別な意味があるようだ。だから、データベースの名前付けにはちょっと注意が必要。

# curl -X GET http://127.0.0.1:5984/_all_dbs
[]

まだデータベースが無いので作る(create database)。PUTメソッドを使う。このあたりがRESTっぽい。ちなみに返って来るステータスもJSONのデータである。Erlangいじったことのある人には馴染みのある返事だろう。

# curl -X PUT http://127.0.0.1:5984/albums
{"ok":true}

データベースが追加されているかどうかの確認をしてみよう。

# curl -X GET http://127.0.0.1:5984/_all_dbs
["alubums"]

重複して追加するとエラーになる

# curl -X PUT http://127.0.0.1:5984/albums
{"error":"db_exists"}

データベースの削除(delete database)もできる。これはDELETEメソッド。

# curl -X DELETE http://127.0.0.1:5984/albums
{"ok":true}

データベースへのJSONドキュメントの追加はPUTメソッドで行う。リクエストのパスにUUIDが必要である。データの内容は -d オプションで指定している。

# curl -X PUT http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0 -d '{"title":"Blackened Sky","artist":"Biffy Clyro", "year":2002}'

UUIDを割り当ててもらうには、/_uuids/ というパスが使える。

# curl -X GET http://127.0.0.1:5984/_uuids
{"uuids":["70b50bfa0a4b3aed1f8aff9e92dc16a0"]}

先の例はこのUUIDを使ったわけだ。
では、このUUIDを使って、登録されたドキュメントにアクセスしてみる。

# curl -X GET http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0
{"_id":"70b50bfa0a4b3aed1f8aff9e92dc16a0","_rev":"1-d789a27476ed3962a24736e4138ff71f","title":"Blackened Sky","artist":"Biffy Clyro","year":2002}

ここで、_rev という項目があるが、これはドキュメントのrevisionを表す。HTTPのレスポンスヘッダではEtagに相当する部分である。この情報を使って、replicationをしているらしい。
curlでは-vのオプションをつけると、その辺りが確認できる。ただし、古いrevisionのデータは何もしないと消えていくのがデフォルトの設定らしい。

ドキュメントに子となる要素をattachする。PUTメソッドでJPEG画像ファイル(artwork.jpg)を添付してみる。このとき、ドキュメントのパスとrevisionを両方とも指定している。

# curl -X PUT http://127.0.0.1:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg?rev=2-2739352689 -d@artwork.jpg -H "Content-Type: image/jpg"

これで、attachされた元のドキュメントにアクセスすると、"_attachments"という要素が追加されていることがわかる。
子要素にダイレクトにアクセスする場合には、次のようにする。

# curl -X GET http://127.0.0.1:5984/albums/70b50bfa0a4b3aed1f8aff9e92dc16a0/artwork.jpg

この場合、GUIで見たほうがいいだろう。

GUIがある

GUI(Futonという名前。まぁCouch=ソファだからな)へのアクセスは/_utils/ というパスで行う。VPSを使っているなら、sshで接続してportforwardして、ブラウザから使うといいかもしれない。

これがOverview。

先ほどPUTした個別のドキュメントを表示した例。

GUIはサーバの状態や設定の確認に使えるが、それぞれ対応するパスがあるので、コマンドラインから叩くこともできる。

  • Overview
# curl -X http://127.0.0.1:5984/_utils/index.html
HTML文書が返ってくる
  • 設定
# curl -X GET http://127.0.0.1:5984/_utils/config.html
これも、HTML文書の内容が返ってくる。
  • 状態:こちらもHTML文書、というかJavascriptの内容が返ってくる。
# curl -X GET http://127.0.0.1:5984/_utils/status.html
<!DOCTYPE html>
以下略


以上、ざっと写経してみた。なんとなくつかめた。今度はブラウザからアクセスするJavascriptの方をいじってみたい。

*1:2009/8/5追記:正確にはオブジェクト指向DBではない。An object-oriented database. Or more specifically, meant to function as a seamless persistence layer for an OO programming language"ではない、と[http://couchdb.apache.org/docs/intro.html:title=Introduction]には断り書きがある。