MongoDB的MapReduce用法及php示例代码_PHP_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > PHP > MongoDB的MapReduce用法及php示例代码

MongoDB的MapReduce用法及php示例代码

 2013/6/19 11:17:58  abc123456789cba  程序员俱乐部  我要评论(0)
  • 摘要:MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有groupby函数那样方便分组,但是MongoDB要实现分组也有3个办法:*Mongodb三种分组方式:*1、group(先筛选再分组,不支持分片,对数据量有所限制,效率不高)*2、mapreduce(基于js引擎,单线程执行,效率较低,适合用做后台统计等)*3、aggregate(推荐)(如果你的PHP的mongodb驱动版本需>=1.3.0,推荐你使用aggregate,性能要高很多
  • 标签:用法 PHP Map 代码 MongoDB

MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有group by函数那样方便分组,但是MongoDB要实现分组也有3个办法:

?

class="p1" style="font-family: Arial; line-height: 26px;">?* 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命令如下: [javascript]?view plaincopy
  1. db.runCommand(??
  2. {?mapreduce?:?<collection>,??
  3. ???map?:?<mapfunction>,??
  4. ???reduce?:?<reducefunction>??
  5. ???[,?query?:?<query?filter?object>]??
  6. ???[,?sort?:?<sort?the?query.??useful?for?optimization>]??
  7. ???[,?limit?:?<number?of?objects?to?return?from?collection>]??
  8. ???[,?out?:?<output-collection?name>]??
  9. ???[,?keeptemp:?<true|false>]??
  10. ???[,?finalize?:?<finalizefunction>]??
  11. ???[,?scope?:?<object?where?fields?go?into?javascript?global?scope?>]??
  12. ???[,?verbose?:?true]??
  13. ?}??
  14. );??

参数说明:

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,测试数据如下: [javascript]?view plaincopy
  1. {??
  2. ???"_id":?ObjectId("50ccb3f91e937e2927000004"),??
  3. ???"feed_type":?1,??
  4. ???"to_user":?234,??
  5. ???"time_line":?"2012-12-16?01:26:00"??
  6. }??
  7. ??
  8. {??
  9. ???"_id":?ObjectId("50ccb3ef1e937e0727000004"),??
  10. ???"feed_type":?8,??
  11. ???"to_user":?123,??
  12. ???"time_line":?"2012-12-16?01:26:00"??
  13. }??
  14. ??
  15. {??
  16. ???"_id":?ObjectId("50ccb3e31e937e0a27000003"),??
  17. ???"feed_type":?1,??
  18. ???"to_user":?123,??
  19. ???"time_line":?"2012-12-16?01:26:00"??
  20. }??
  21. ??
  22. {??
  23. ???"_id":?ObjectId("50ccb3d31e937e0927000001"),??
  24. ???"feed_type":?1,??
  25. ???"to_user":?123,??
  26. ???"time_line":?"2012-12-16?01:26:00"??
  27. }??

我们按动态类型feed_type和用户to_user进行分组统计,实现结果: feed_type to_user cout 1 234 1 8 123 1 1 123 2 ? ? ? ? ? ? ? 实现代码: ? [php]?view plaincopy
  1. //编写map函数??
  2. $map?=?'??
  3. ?????function()?{??
  4. ??????var?key?=?{to_user:this.to_user,feed_type:this.feed_type};??
  5. ??????var?value?=?{count:1};??
  6. ??????emit(key,value);??
  7. ????}?';???
  8. ??
  9. //reduce?函数??
  10. $reduce?=?'??
  11. ?????function(key,?values)?{??
  12. ?????????var?ret?=?{count:0};??
  13. ?????for(var?i?in?values)?{??
  14. ??????????ret.count?+=?1;??
  15. ??????}??
  16. ??????return?ret;??
  17. ??????}';??
  18. ??
  19. //查询条件??
  20. $query?=?null;??//本实例中没有查询条件,设置为null??
[php]?view plaincopy
  1. $mongo?=?new?Mongo('mongodb://root:root@127.0.0.1:?28017/');?//链接mongodb,账号和密码为root,root??
  2. $instance?=?$mongo->selectDB("testdb");??
  3. ??
  4. //执行此命令后,会创建feed_temp_res的临时集合,并将统计后的数据放在该集合中??
  5. $cmd?=?$instance->command(array(??
  6. ????????'mapreduce'?=>?'feed',??
  7. ????????'map'???????=>?$map,??
  8. ????????'reduce'????=>?$reduce,??
  9. ????????'query'?=>?$query,??
  10. ????????'out'?=>?'feed_temp_res'??
  11. ));??
  12. ??
  13. //查询临时集合中的统计数据,验证统计结果是否和预期结果一致??
  14. $cursor?=?$instance->selectCollection('feed_temp_res')->find();??
  15. $result?=?array();??
  16. try?{??
  17. ????while?($cursor->hasNext())??
  18. ????{??
  19. ????????$result[]?=?$cursor->getNext();??
  20. ????}??
  21. }??
  22. catch?(MongoConnectionException?$e)??
  23. {??
  24. ????echo?$e->getMessage();??
  25. }??
  26. catch?(MongoCursorTimeoutException?$e)??
  27. {??
  28. ????echo?$e->getMessage();??
  29. }??
  30. catch(Exception?$e){??
  31. ????echo?$e->getMessage();??
  32. }??
  33. ??
  34. //test??
  35. var_dump($result);??

下面是输出的结果,和预期结果一致 ? [javascript]?view plaincopy
  1. {??
  2. ???"_id":?{??
  3. ?????"to_user":?234,??
  4. ?????"feed_type":?1???
  5. ??},??
  6. ???"value":?{??
  7. ?????"count":?1???
  8. ??}???
  9. }??
  10. ??
  11. {??
  12. ???"_id":?{??
  13. ?????"to_user":?123,??
  14. ?????"feed_type":?8???
  15. ??},??
  16. ???"value":?{??
  17. ?????"count":?1???
  18. ??}???
  19. }??
  20. ??
  21. {??
  22. ???"_id":?{??
  23. ?????"to_user":?123,??
  24. ?????"feed_type":?1???
  25. ??},??
  26. ???"value":?{??
  27. ?????"count":?2???
  28. ??}???
  29. }??


以上只是简单的统计实现,你可以实现复杂的条件统计编写复杂的reduce函数,可以增加查询条件,排序等等。 ? 附上mapReduce数据库处理函数(简单封装) [php]?view plaincopy
  1. /**?
  2. ?*?mapReduce分组?
  3. ?*??
  4. ?*?@param?string?$table_name?表名(要操作的目标集合名)?
  5. ?*?@param?string?$map?映射函数(生成键值对序列,作为?reduce?函数参数)??
  6. ?*?@param?string?$reduce?统计处理函数?
  7. ?*?@param?array??$query?过滤条件?如:array('uid'=>123)?
  8. ?*?@param?array??$sort?排序?
  9. ?*?@param?number?$limit?限制的目标记录数?
  10. ?*?@param?string?$out?统计结果存放集合?(不指定则使用tmp_mr_res_$table_name,?1.8以上版本需指定)?
  11. ?*?@param?bool???$keeptemp?是否保留临时集合?
  12. ?*?@param?string?$finalize?最终处理函数?(对reduce返回结果进行最终整理后存入结果集合)?
  13. ?*?@param?string?$scope?向?map、reduce、finalize?导入外部js变量?
  14. ?*?@param?bool???$jsMode?是否减少执行过程中BSON和JS的转换,默认true(注:false时?BSON-->JS-->map-->BSON-->JS-->reduce-->BSON,可处理非常大的mapreduce,//true时BSON-->js-->map-->reduce-->BSON)?
  15. ?*?@param?bool???$verbose?是否产生更加详细的服务器日志?
  16. ?*?@param?bool???$returnresult?是否返回新的结果集?
  17. ?*?@param?array??&$cmdresult?返回mp命令执行结果?array("errmsg"=>"","code"=>13606,"ok"=>0)?ok=1表示执行命令成功?
  18. ?*?@return??
  19. ?*/??
  20. 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){??
  21. ????if(empty($table_name)?||?empty($map)?||?empty($reduce)){??
  22. ????????return?null;??
  23. ????}??
  24. ????$map?=?new?MongoCode($map);??
  25. ????$reduce?=?new?MongoCode($reduce);??
  26. ????if(empty($out)){??
  27. ????????$out?=?'tmp_mr_res_'.$table_name;??
  28. ????}??
  29. ????$cmd?=?array(??
  30. ????????????'mapreduce'?=>?$table_name,??
  31. ????????????'map'???????=>?$map,??
  32. ????????????'reduce'????=>?$reduce,??
  33. ????????????'out'???????=>$out??
  34. ????);??
  35. ????if(!empty($query)?&&?is_array($query)){??
  36. ????????array_push($cmd,?array('query'=>$query));??
  37. ????}??
  38. ????if(!empty($sort)?&&?is_array($sort)){??
  39. ????????array_push($cmd,?array('sort'=>$query));??
  40. ????}??
  41. ????if(!empty($limit)?&&?is_int($limit)?&&?$limit>0){??
  42. ????????array_push($cmd,?array('limit'=>$limit));??
  43. ????}??
  44. ????if(!empty($keeptemp)?&&?is_bool($keeptemp)){??
  45. ????????array_push($cmd,?array('keeptemp'=>$keeptemp));??
  46. ????}??
  47. ????if(!empty($finalize)){??
  48. ????????$finalize?=?new?Mongocode($finalize);??
  49. ????????array_push($cmd,?array('finalize'=>$finalize));??
  50. ????}??
  51. ????if(!empty($scope)){??
  52. ????????array_push($cmd,?array('scope'=>$scope));??
  53. ????}??
  54. ????if(!empty($jsMode)?&&?is_bool($jsMode)){??
  55. ????????array_push($cmd,?array('jsMode'=>$jsMode));??
  56. ????}??
  57. ????if(!empty($verbose)?&&?is_bool($verbose)){??
  58. ????????array_push($cmd,?array('verbose'=>$verbose));??
  59. ????}??
  60. ????$dbname?=?$this->curr_db_name;??
  61. ????$cmdresult?=?$this->mongo->$dbname->command($cmd);??
  62. ????if($returnresult){??
  63. ????????if($cmdresult?&&?$cmdresult['ok']==1){??
  64. ????????????$result?=?$this->find($out,?array());??
  65. ????????}??
  66. ????}??
  67. ????if($keeptemp==false){??
  68. ????????//删除集合??
  69. ????????$this->mongo->$dbname->dropCollection($out);??
  70. ????}??
  71. ????return?$result;??
  72. }??


MongoDB官方网站介绍: ? MapReduce介绍?http://docs.mongodb.org/manual/core/map-reduce/

Aggregation介绍?http://docs.mongodb.org/manual/aggregation/ ? http://blog.csdn.net/slimboy123/article/details/8909974
发表评论
用户名: 匿名