MongoDBの薄い本の素材をMongoidでやろうとしたけど途中経過
MapReduceをやることの利点は、並列処理ができるということとSQLより柔軟な処理なできるということらしい(MongoDBにはまだ並列処理の機能はない)
Model
1 2 3 4 5 | class Log include Mongoid::Document field :uri, type: String field :access, type: Date end |
seed.db(test data)
1 2 3 4 5 6 7 8 9 10 11 | 100.times do year = 2000 + rand(13) month = 1 + rand(12) day = 1 + rand(28) uris = [ "", "about", "infomation"] p year*10000 + month*100 + day Log.create({ uri: "/" + uris[rand(3)], access: Time.new(year, month, day) }) end |
rails cで以下を貼り付けるとlogstatというコレクションに集計データが挿入される
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | map = <<MAP function() { var key = {uri: this.uri, year: this.access.getFullYear(), month: this.access.getMonth(), day: this.access.getDate() }; emit(key, {count: 1}); }; MAP reduce = <<REDUCE function(key, values) { var sum = 0; values.forEach(function(value) { sum += value['count']; }); return {count: sum}; }; REDUCE Log.map_reduce(map,reduce).out(replace: "logstat") |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | > db.logstat.find() { "_id" : { "uri" : "/", "year" : 2000, "month" : 7, "day" : 5 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2000, "month" : 8, "day" : 23 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2001, "month" : 0, "day" : 24 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2001, "month" : 0, "day" : 25 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2001, "month" : 4, "day" : 28 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2001, "month" : 7, "day" : 4 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2001, "month" : 11, "day" : 6 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2002, "month" : 4, "day" : 3 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2003, "month" : 0, "day" : 6 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2003, "month" : 9, "day" : 15 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2004, "month" : 4, "day" : 28 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2004, "month" : 8, "day" : 3 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2005, "month" : 10, "day" : 14 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2006, "month" : 2, "day" : 4 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2006, "month" : 7, "day" : 15 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2006, "month" : 8, "day" : 17 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2007, "month" : 0, "day" : 17 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2007, "month" : 3, "day" : 4 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2007, "month" : 11, "day" : 7 }, "value" : { "count" : 1 } } { "_id" : { "uri" : "/", "year" : 2008, "month" : 0, "day" : 11 }, "value" : { "count" : 1 } } Type "it" for more |
・・・しまった randの値を大きく取りすぎて集計の意味が無い!
今までのハマリポイント
- map_reduceに渡すjavascriptのstringはすぐ実行する形で(無名関数でOK)。最初薄い本から直接コピペしてvar map = function(){….で渡していたら、うんともすんとも言わずログにも何も出ずで悩んだ。当たり前
- out(replace: “logstat”)とかのシンボル:replaceとかがミススペルでもなぜかエラーがでなかった
- まだなぜかRailsアプリからの実行がうまくいかない。。。情報が少なすぎるorz
酸っぱいブドウ
RailsからMongoDBを使う大きな利点のひとつはMongoDBがスキーマレスなのでRDBMSの制約を気にせずにRubyのレイヤーだけで柔軟に制約を書けることだという気がする
すると、Railsの場合は集計などの操作もrubyでやればいいので、ことさらに不細工なstringでjavascriptを突っ込んでまでやる必要はあまりないんじゃないだろうか