MongoDB雖然不像我們常用的mysql,sqlserver,oracle等關係型資料庫有group by函數那樣方便分組,但是MongoDB要實現分組也有3個辦法:
* Mongodb三種分組方式:
* 1、group(先篩選再分組,不支援分區,對資料量有所限制,效率不高)
* 2、mapreduce(基於js引擎,單線程執行,效率較低,適合用做後台統計等)
* 3、aggregate(推薦) (如果你的PHP的mongodb驅動版本需>=1.3.0,推薦你使用aggregate,效能要高很多,並且使用上要簡單些,不過1.3的目前還不支援賬戶認證模式,可以通過 http://pecl.php.net/package/mongo 查看更新日誌和Bug)
下面就來看下mapreduce方式:
Mongodb官網對MapReduce介紹:
Map/reduce in MongoDB is useful for batch processing of data and aggregation operations. It is similar in spirit to using something like Hadoop with all input coming from a collection and output going to a collection. Often, in a situation where you would have used GROUP BY in SQL, map/reduce is the right tool in MongoDB.
大致意思是: Mongodb中的Map/reduce主要是用來對資料進行批量處理和彙總操作,有點類似於使用Hadoop對集合資料進行處理,所有輸入資料都是從集合中擷取,而MapReduce後輸出的資料也都會寫入到集合中。通常類似於我們在SQL中使用Group By語句一樣。
使用MapReduce要實現兩個函數:Map和Reduce。Map函數調用emit(key,value)遍曆集合中所有的記錄,將key與value傳給Reduce函數進行處理。Map函數和Reduce函數是使用Javascript編寫的,並可以通過db.runCommand或mapreduce命令來執行MapReduce操作。
MapReduce命令如下:
db.runCommand({ mapreduce : <collection>, map : <mapfunction>, reduce : <reducefunction> [, query : <queryfilterobject>] [, sort : <sortthequery.usefulforoptimization>] [, limit : <numberofobjectstoreturnfromcollection>] [, out : <output-collectionname>] [, keeptemp: <true|false>] [, finalize : <finalizefunction>] [, scope : <objectwherefieldsgointojavascriptglobalscope >] [, verbose : true] });
參數說明:
mapreduce:要操作的目的地組合
map:映射函數(產生鍵值對序列,作為Reduce函數的參數)
reduce:統計函數
query:目標記錄過濾
sort:對目標記錄排序
limit:限制目標記錄數量
out:統計結果存放集合(如果不指定則使用臨時集合,在用戶端斷開後自動刪除)
keeptemp:是否保留臨時集合
finalize:最終處理函數(對reduce返回結果執行最終整理後存入結果集合)
scope:向map、reduce、finalize匯入外部變數
verbose:顯示詳細的時間統計資訊
map函數
map函數調用當前對象,並處裡對象的屬性,傳值給reduce,map方法使用this來操作當前對象,最少調用一次emit(key,value)方法來向reduce提供參數,其中emit的key為最終資料的id。
reduce函數
接收一個值和數組,根據需要對數組進行合并分組等處理,reduce的key就是emit(key,value)的key,value_array是同個key對應的多個value數組。
Finalize函數
此函數為可選函數,可在執行完map和reduce後執行,對最後的資料進行統一處理。
看完基本介紹,我們再來看一個執行個體:
已知集合feed,測試資料如下:
{ "_id": ObjectId("50ccb3f91e937e2927000004"), "feed_type": 1, "to_user": 234, "time_line": "2012-12-16 01:26:00"}{ "_id": ObjectId("50ccb3ef1e937e0727000004"), "feed_type": 8, "to_user": 123, "time_line": "2012-12-16 01:26:00"}{ "_id": ObjectId("50ccb3e31e937e0a27000003"), "feed_type": 1, "to_user": 123, "time_line": "2012-12-16 01:26:00"}{ "_id": ObjectId("50ccb3d31e937e0927000001"), "feed_type": 1, "to_user": 123, "time_line": "2012-12-16 01:26:00"}
我們按動態類型feed_type和使用者to_user進行分組統計,實現結果:
| feed_type |
to_user |
cout |
| 1 |
234 |
1 |
| 8 |
123 |
1 |
| 1 |
123 |
2 |
實現代碼:
//編寫map函數$map = ' function() { var key = {to_user:this.to_user,feed_type:this.feed_type}; var value = {count:1}; emit(key,value); } '; //reduce 函數$reduce = ' function(key, values) { var ret = {count:0}; for(var i in values) { ret.count += 1; } return ret; }';//查詢條件$query = null; //本執行個體中沒有查詢條件,設定為null$mongo = new Mongo('mongodb://root:root@127.0.0.1: 28017/'); //連結mongodb,帳號和密碼為root,root$instance = $mongo->selectDB("testdb");//執行此命令後,會建立feed_temp_res的臨時集合,並將統計後的資料放在該集合中$cmd = $instance->command(array('mapreduce' => 'feed','map' => $map,'reduce' => $reduce,'query'=> $query,'out' => 'feed_temp_res'));//查詢臨時集合中的統計資料,驗證統計結果是否和預期結果一致$cursor = $instance->selectCollection('feed_temp_res')->find();$result = array();try {while ($cursor->hasNext()){$result[] = $cursor->getNext();}}catch (MongoConnectionException $e){echo$e->getMessage();}catch (MongoCursorTimeoutException $e){echo$e->getMessage();}catch(Exception$e){echo$e->getMessage();}//testvar_dump($result);
下面是輸出的結果,和預期結果一致
{ "_id": { "to_user": 234, "feed_type": 1 }, "value": { "count": 1 }}{ "_id": { "to_user": 123, "feed_type": 8 }, "value": { "count": 1 }}{ "_id": { "to_user": 123, "feed_type": 1 }, "value": { "count": 2 }}
以上只是簡單的統計實現,你可以實現複雜的條件統計編寫複雜的reduce函數,可以增加查詢條件,排序等等。
附上mapReduce資料庫處理函數(簡單封裝)
/** * mapReduce分組 * * @param string $table_name 表名(要操作的目的地組合名) * @param string $map 映射函數(產生鍵值對序列,作為 reduce 函數參數) * @param string $reduce 統計處理函數 * @param array $query 過濾條件 如:array('uid'=>123) * @param array $sort 排序 * @param number $limit 限制的目標記錄數 * @param string $out 統計結果存放集合 (不指定則使用tmp_mr_res_$table_name, 1.8以上版本需指定) * @param bool $keeptemp 是否保留臨時集合 * @param string $finalize 最終處理函數 (對reduce返回結果進行最終整理後存入結果集合) * @param string $scope 向 map、reduce、finalize 匯入外部js變數 * @param bool $jsMode 是否減少執行過程中BSON和JS的轉換,預設true(註:false時 BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可處理非常大的mapreduce,//true時BSON-->js-->map-->reduce-->BSON) * @param bool $verbose 是否產生更加詳細的伺服器日誌 * @param bool $returnresult 是否返回新的結果集 * @param array &$cmdresult 返回mp命令執行結果 array("errmsg"=>"","code"=>13606,"ok"=>0) ok=1表示執行命令成功 * @return*/ function mapReduce($table_name,$map,$reduce,$query=null,$sort=null,$limit=0,$out='',$keeptemp=true,$finalize=null,$scope=null,$jsMode=true,$verbose=true,$returnresult=true,&$cmdresult){ if(empty($table_name) || empty($map) || empty($reduce)){ return null; } $map = new MongoCode($map); $reduce = new MongoCode($reduce); if(empty($out)){ $out = 'tmp_mr_res_'.$table_name; } $cmd = array( 'mapreduce' => $table_name, 'map' => $map, 'reduce' => $reduce, 'out'=>$out ); if(!empty($query) && is_array($query)){ array_push($cmd, array('query'=>$query)); } if(!empty($sort) && is_array($sort)){ array_push($cmd, array('sort'=>$query)); } if(!empty($limit) && is_int($limit) && $limit>0){ array_push($cmd, array('limit'=>$limit)); } if(!empty($keeptemp) && is_bool($keeptemp)){ array_push($cmd, array('keeptemp'=>$keeptemp)); } if(!empty($finalize)){ $finalize = new Mongocode($finalize); array_push($cmd, array('finalize'=>$finalize)); } if(!empty($scope)){ array_push($cmd, array('scope'=>$scope)); } if(!empty($jsMode) && is_bool($jsMode)){ array_push($cmd, array('jsMode'=>$jsMode)); } if(!empty($verbose) && is_bool($verbose)){ array_push($cmd, array('verbose'=>$verbose)); } $dbname = $this->curr_db_name; $cmdresult = $this->mongo->$dbname->command($cmd); if($returnresult){ if($cmdresult && $cmdresult['ok']==1){ $result = $this->find($out, array()); } } if($keeptemp==false){ //刪除集合 $this->mongo->$dbname->dropCollection($out); } return$result; }
MongoDB官方網站介紹:
MapReduce介紹 http://docs.mongodb.org/manual/core/map-reduce/
Aggregation介紹 http://docs.mongodb.org/manual/aggregation/
以上就介紹了mongodb的mapreduce用法及php範例程式碼,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。