注意: 現在のところ、shardの環境では、group()の代わりにmap/reduceを必ず使ってください。
結果はなるべく小さくしてください(10,000キー以内)。大きすぎる場合例外が発生します。Shard環境では問答無用にMap Reduceを使うしかなさそうです。結果はなるべく小さくしろと言うことですが、10000キーあればそこそこ大きいような気がします。最初の制限の「現在のところ」というのが気にならなくもないですが、処理結果はMapReduceと大差ないし、MapReduceの方がもう少しいろいろできそうな気もします。たとえば、結果は実行後すぐに取得できますが、これをコレクションとしてMongoDBの中に永続化するとかです。なので、groupメソッドはいらねんじゃね?Map Reduceだけで十分じゃね?と思います。
さて、それで、MapReduceですが、map関数とreduce関数をJavaScriptで書くだけです。PythonでもJavaScriptです。はい。それ以外にもfinalizeするときのメソッドも定義できます。マニュアルをよむと、結果で平均値を求めたりするらしいです。reduceの中でやっちゃえばいいような気もするので、あまり使い道を思いつきません。
それじゃ、コードのお時間です。
import pymongo import pymongo from pymongo.code import Code conn = pymongo.Connection() tbl = conn.my_db.my_table m = Code(""" function() { emit(this.url, this); } """) r = Code(""" function(key, values) { var total = 0; var len = values.length; for (var i=0; i<len; i++) { total += values[i].count; } var url = values[0].url; return { count:total, url: url}; } """) res = tbl.map_reduce(m, r for r in res.find(): print r["value"]["count"]
my_tableは、urlとcountというフィールドを持ちます。それぞれ文字列と数字です。map関数はmです。これは、URLをキーとしてemitしてます。valueはめんどいのでレコード自身です。rがreduce関数になります。これは、valuesはemitしたvalueが配列になって渡されます。一個づつイテレートしながらcountの光景を求めています。終わったら、countとurlを返しています。
map_reduceで実行すると結果として、コレクションが返されます。このコレクションに対して、findなどいろいろできます。結果を永続化するにはout="result"という引数をmap_reduceに追加してあげればよいです。簡単です。
新しく作られたコレクションは、keyとvalueという二つのフィールドからなります。キーはreduce関数に渡されたものです。valueはreduce関数が返したものです。
group関数を使った場合は、結果が配列ですべてオンメモリで返されます。ソートを行うにしても自前でソートしないと行けません。いやんですね。
まあ、groupは使わずにmap reduceでよくね?という話です。
でわでわ。
2 件のコメント:
速度が全然違いますが
でも、シャード環境で使えない、件数が多いとメモリに全部展開されるのでスケーラブルでない、など制限がありすぎて、多くの場合、速度のメリットよりデメリットが上回ると思っています。
コメントを投稿