Gem漁りをしていたら興味深いものを見つけました。Monetaというものです。Monetaとは様々な種類のデータベースを統一的なインターフェースで使用することができるRuby Gemです。使用することができるのはKVSだけではなく、Sqlite3など一部のRDBにも対応しているようです。
メリットとして主張されているのは、バックエンドの容易な切り替えです。最初はインメモリストアでテストし、後でKVSに切り替えるといったことが、最小の変更でできるでしょう。
そのような切り替えを実際にやるかどうかはさておいて、バックエンドタイプによらない統一的なプログラミングというのはそれだけで魅力に感じました。KVSの選択に迷っている段階でもコードを書き始めることができるからです。
ここではとりあえずPStore, Daybreak, KyotoCabinet, LevelDB(選択は適当…)の4種に対して書き込みと読み込みのプログラムを書いてみました。
統一的なプログラミングが可能であるというメリットを確認しようと思ったのですが、後述するように注意点もあります。
データベース作成のサンプル
まずは書き込みから。
require 'moneta'
STORE = {
PStore: {file: "tmp/pstore"},
Daybreak: {file: "tmp/daybreak"},
KyotoCabinet: {file: "tmp/kc.kch"},
LevelDB: {dir: "tmp/leveldb"}
}
def make_db(store_type)
store = Moneta.new(store_type, STORE[store_type])
store.clear
store["Hello"] = "there"
store["It"] = "works"
store["See"] = "you"
ensure
store.close unless store.nil?
end
if ARGV[0].nil?
puts "Usage: ruby #{__FILE__} [#{STORE.keys.join('|')}]"
else
make_db ARGV[0].to_sym
end
このプログラムをruby moneta-write.rb KyotoCabinet
などとして実行すると、バックエンドタイプに応じたファイルがtmp
ディレクトリ以下に作成されます。
プログラムは一見してわかるように、MonetaのインスタンスをHash風に操作するのみ。非常に簡単です。
コンストラクタにはバックエンドのタイプ(シンボル)とファイル名などのオプション(Hash)を渡します。
オプションはバックエンドタイプに依存するようです。ファイル名のキーはほぼfileですが、LevelDBはディレクトリを作成するのでdirというキーで指定する必要があります。
データベース読み取りのサンプル
require 'moneta'
STORE = {
PStore: {file: "tmp/pstore"},
Daybreak: {file: "tmp/daybreak"},
KyotoCabinet: {file: "tmp/kc.kch"},
LevelDB: {dir: "tmp/leveldb"}
}
def show_db(store_type)
store = Moneta.new(store_type, STORE[store_type])
puts "Hello " + store["Hello"]
puts "It " + store["It"]
puts "See " + store["See"]
ensure
store.close unless store.nil?
end
if ARGV[0].nil?
puts "Usage: ruby #{__FILE__} [#{STORE.keys.join('|')}]"
else
show_db ARGV[0].to_sym
end
やっていることはほぼmoneta-write.rb
と同じです。
注意点
- 「素の」データベースとの互換性が一部ない(?): Monetaで作成したKyotoCabinetのファイルは素の(Monetaでラップしていない)KyotoCabinetで読めそうですが、残念ながら正しく読めません。LevelDBも同様です。逆に素のKyotoCabinetで作成したファイルもMonetaでは正しく読めません。PStoreとDaybreakについては問題ないようです。これらはMonetaと素のDBの間に互換性があります。
- サポートされないメソッド: 一部KVSでは使用できるメソッドでもMonetaでは使用できないことがあります。例えば
#each
など。