2011年6月10日金曜日

MongoDBと戯れる その2

今回は覚書、読むだけじゃ覚えないので、書きながらサマリーしてみる。

そもそも概念がちょっと違う。

普通にデータベースを持つ

Collection

CollectionというのがRDBMSでいうところのテーブルに値する。
  db.students --> studentsというcollectionが存在する。
内部表現はJSON形式であらわすことができる。実はBSONという形式ぱっと見た感じ、JSONだけどちょっと違う。
よりオブジェクト指向的な形になっている。
 db.students
  name: 'yas',
     addressHd: {
      address: XXXXX,
      city: Edogawa,
      prefecture: Tokyo
     }

参照

例えば、別のcollectionに対して参照を持つ場合はfor_【collection名】と書けばよい。
 db.students
    name: 'yas',
    for_course:  #参照をあらわしている。

 db.course
  name: 'Biology'
参照するよりも、埋め込んだほうが早いらしい。これは非正規化して速度稼ぐのと同じ理屈。
 1:Mongo的な非正規化
  db.students
    name: 'yas'
    address: 'XXXX'
    score: 
     { name: 'biology',
     grade: 4.0},
 
 2:Mongo的な正規化
  db.students
    name: 'yas'
    score: 
      { for_cource
          grade: 4.0}
    
    db.cource
      name: 'biology'
呼び出し側を考えれば簡単
1の場合: print(student.cource)
2の場合: print(student.score[0].for_course.name)
--> 内部的には、student.scores[0].for_course = db.courses.findOne({_id:_course_id_to_find_});
こういうノリのよう。
なので、場合によって使い分けたほうが良いはず。
非正規化する際、Gridとかのデータとかは出来上がったものを持てば良いだけなので問題ない。
それ以外の属性に依存する形の場合にはちょっと考えたほうが良い。2でガツガツ呼ばれる(1000)とか来ると
といくらキャッシュとはいえ1秒以上かかってしまうので。そこら辺は良く考えて!!だそうだ。

一般的なルール

  • ノード的にトップレベルのものは独自のコレクションを持つほうが良い
  • LineItemは(要するに詳細情報とかは)埋め込んどけ。
  • Object contains A の形になる場合は埋め込んどけ。
  • Many to Many なる場合はどうしようもないので、参照で持つしかない。
  • 集計とか統計とかするのであれば埋め込んどかないと時間かかって仕方ない。
→要するに基本的には埋め込んどけ。MtoMをどうしても表現しないといけなくなったときだけ参照使え。

indexはRDBMSと同じノリで張れば大丈夫。

  • _idは勝手にindexが張られている。これはputした瞬間にMongoが突っ込んでくれる。サロゲートキー
  • sortされるところはindexはっといたほうが良い→これは要検証。

tree表現とかも使える。


結構用意されていて、treeとしても使える。
tree情報のキャッシュには良いかもしれない。

デフォルトポート

27017

シェル

Mongoがそれにあたる。JavaScriptなシェル。これ面白い

制約

32bit環境においてstorageの限界は2Gbyteまで。

ちょっと試してみた結果

環境WindowsXP 32bit CPM core2 DUO Memory:4G
使用言語MongoDBのJavaドライバー経由でJava
対象件数3万件
ローカルストレージの変遷72,920byte
実行時間5891ミリ秒
使用メモリ量70Mぐらい

実験に使ったコード

ちなみにthis.excは適当に書いてみた。ラッパー
 long t1 = System.currentTimeMillis();
    System.out.println("計測開始!!" + t1);
    for (int i = 0; i < 30000; i++) {
      DBObject doc = new BasicDBObject();
      String str = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
      doc.put("name", str);
      doc.put("name_1", str);
      doc.put("name_2", str);
      doc.put("name_3", str);
      doc.put("name_4", str);
      doc.put("name_5", str);
      doc.put("name_6", str);
      doc.put("name_7", str);
      doc.put("name_8", str);
      doc.put("name_9", str);
      doc.put("name_10", str);
      doc.put("name_12", str);
      doc.put("name_13", str);
      doc.put("name_14", str);
      doc.put("name_15", str);
      this.exc.insert(doc);
    }
    long t2 = System.currentTimeMillis();
    System.out.println("結果:" + (t2 - t1) + "milSec");
    System.out.println("レコード数" + this.exc.getCount());
まだまだわからないことだらけだ。もっと検証を進めていこう。

2011年6月9日木曜日

MongoDB覚え書き

これは良いかもしれない!jarもあるし、windows版もある。
しかも、sortも出来るし、searchもOK。尚かつ、出力形式もJSONな感じだし。
これは、僕の為に作ってくれたのか!!!ぐらい有り難いです。
というわけで、色々メモしておこう。

ノリ的にはSqlite

   //Mongoサーバに接続する。この場合はlocalhost
   Mongo mongo = new Mongo("localhost");
  //使用するdatabaseを選択する。無ければ作ってくれる。
   DB db = mongo.getDB("myDb");
  //ここで対象のカラム群を選ぶ。無くてもOK.ノリ的には、tableという感じ。
   DBCollection coll = db.getCollection("testCol");
後は、このcollに対して操作をしてくのが基本。

データをinsertする。

  //こいつがその名の通り、基本のオブジェクト。
  BasicDBObject doc = new BasicDBObject();
  //insertするのは、他のkvsとかと同じ様にputでOK。
  doc.put("name", "yas");
  doc.put("age", 30);
   //上記のままではまだ保存されていないので、保存はこんな感じ。
   DBCollection coll = db.getCollection("testCol");
   //ここでコレクションに対してinsertが走ります。
   coll.insert(doc);

データをselectする。

■一件欲しい時
           DBObject myDoc = coll.findOne();
    System.out.println(myDoc);
■全部欲しいとき
    DBCollection coll = db.getCollection("testCol");
    DBCursor cursor = coll.find();
    while(cursor.hasNext()){
          System.out.println(cursor.next());
     }
■もっと絞りたいとき
               DBCollection coll = db.getCollection("testCol");
                //ここで検索条件を作っています。
  BasicDBObject query = new BasicDBObject();
         query.put("i", new BasicDBObject("$ne",3));
    //findする引数に問い合わせ条件を伴います。
  DBCursor cursor = coll.find(query);
         while(cursor.hasNext()) {
             System.out.println(cursor.next());
         }
■ソートもしたい
         DBCollection coll = db.getCollection("testCol");
  BasicDBObject query = new BasicDBObject();
         query.put("i", new BasicDBObject("$ne",3));
  BasicDBObject orderBy = new BasicDBObject();
                //-1だとDESCになります。
  orderBy.put("i", -1);
  DBCursor cursor = coll.find(query).sort(orderBy);
         while(cursor.hasNext()) {
             System.out.println(cursor.next());
         }
と言う感じらしい。リミットもひけるのでとても良い感じだと思う。
MongoDB最強伝説が始まっちゃったかな?
明日は、もっとデータをぶち込んで実際にJSON --> HTMLにmappingするところまでやってみよう。
これならいけるぞ!これなら!!

TokyoTyrantと戯れる その弐: Javaで使う。

メインの言語はJavaです。悲しいけど。
だから、Javaで動くまでを書いてみます。
まずはライブラリを探索。ここにある。
権利関係も大事だな、こいつのライセンスはApacheLicense2.0。よし、問題ない!
というわけで、ドキュメントを読み漁っていると問題発覚。。。
てか、RDBTable使えない。。。NightlyBuild的なソースが転がってたけど、
さすがにこれは使えない。。。ごめんね、作った人。
と言うわけで、JRubyかなぁとか思って、JRubyも試してみる。
すると、こんどはJava1.6からじゃないとすっきり書けない。。。
ScriptEngineManagerっていJava1.6からしか使えないし。。。乙 :P
と言うわけで、探しまくったら
こんなの見つけた。
これはどうなんだろう?ドキュメントを読んでいくとこれはRdbTableをサポートしてくれているらしい。早速トライ!!
ってLinux上でどうしてもコンパイル出来なかった。。。
険しいなぁ、ちょっと寄り道してMongoDbでも見てみよう。

2011年6月8日水曜日

TokyoTyrantことはじめ

色々と紆余曲折があって、TokyoTyrantを試してみることになった。
もともと、rubyな人だったので、まずはrubyで試してみる。

インストール

まずはインストール、適当に用意してあったVmWare上のCentOsに放り込む
Cabinet,Tyrant,TyrantRubyをイントール。必要なライブラリが足りなかったので、下記で充当。
yum -y install zlib-devel
yum -y install bzip*
それぞれのライブラリは
configure
make
make install
でOKだった。簡単。簡単。
rubyバインディングはinstall.rbがあったので、そいつを叩けば終了。
これで、とりあえず準備は整った。
今回は、2次元のデータ構造(Grid形式のもの)を放り込みたかったので、
テーブルのタイプは、tchではなく、tctを選択することにする。
ttservctlをエディタで開いて、拡張子を変更する。(tch -> tct)
dbname="$basedir/casket.tct#bnum=1000000"
そしてサーバ再起動
 ttservctl stop
 ttservctl start
最もシンプルなコードでテスト。
 require 'tokyotyrant'
 include TokyoTyrant
 #このRDBTBLを利用する為に、拡張子をかえました。
 db = RDBTBL::new
 if !db.open('localhost',1978)
   p 'not connected'
 end
 #putの反対はout,outするとメモリ上からさようなら。
 if !db.put("row1",{"name" => "cat", "age" => "18"})
   p 'put error'
 end
 db.put("row2",{"name" => "dog", "age" => "19"})
 db.put("row3", {"name" => "lion","age" => "20"})
 qry = RDBQRY::new(db)
 #sortしてみる。
 qry.setorder("age",RDBQRY::QONUMDESC)
 #MYSQLのlimitと同じ、結果セットから1件だけ下さい。
 qry.setlimit(1)
 p qry.search
 p qry.searchcount
 if !db.close
  p 'not disconnected'
 end
結果は、
 ["row3"]
 1
よしよし、期待通り。次はJavaだな。