`
yidongkaifa
  • 浏览: 4070973 次
文章分类
社区版块
存档分类
最新评论

MongoDB mapReduce和Spring Data配合使用详解

 
阅读更多

经过几天的折腾, 终于弄明白了MongoDB mapReduce在和Spring Data配合使用的方法,简单来说,首先要弄清楚什么是Map Reduce,为什么我们要用map reduce做统计,一般来说, 对应sql语句的group by的场景,都需要用到map reduce。 map reduce的map函数和reduce函数都是javascript写的,因此先要在mongo client先跑通,然后再到spring里面集成。 具体如下:



来源 http://xiaofancn.iteye.com/blog/1184712

MapReduce是一个编程模型,封装了并行计算、容错、数据分布、负载均衡等细节问题。

输入是一个key-value对的集合,中间输出也是key-value对的集合,用户使用两个函数:Map和Reduce。

在使用MongoDb的mapreduce功能时,我找Java代码找半天,结果练了半天的Javascript代码。

MongoDb是通过解析“Javascript”代码来计算的。所有我们先用Javascript代码调通,再使用Java代码拼接使用这个MapReduce功能。

Java代码收藏代码
  1. db.runCommand(
  2. {
  3. mapreduce:<collection>,
  4. map:<mapfunction>,
  5. reduce:<reducefunction>
  6. [,query:<queryfilterobject>]
  7. [,sort:<sortthequery.usefuloptimization>]for
  8. [,limit:<numberofobjectstofromcollection>]return
  9. [,out:<output-collectionname>]
  10. [,keeptemp:<|>]truefalse
  11. [,finalize:<finalizefunction>]
  12. [,scope:<objectwherefieldsgointojavascriptglobalscope>]
  13. [,verbose:]true
  14. });

参数说明:

  • mapreduce: 要操作的目标集合。
  • map: 映射函数 (生成键值对序列,作为 reduce 函数参数)。
  • reduce: 统计函数。
  • query: 目标记录过滤。
  • sort: 目标记录排序。
  • limit: 限制目标记录数量。
  • out: 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
  • keeptemp: 是否保留临时集合。
  • finalize: 最终处理函数 (对 reduce 返回结果进行最终整理后存入结果集合)。
  • scope: 向 map、reduce、finalize 导入外部变量。
  • verbose: 显示详细的时间统计信息

先看看我们的文档结果


我使用上一篇文章插入数据http://xiaofancn.iteye.com/blog/1163200

讲讲我们要实现的功能,就是按照名字name统计记录个数。

Java代码收藏代码
  1. D:\ProgramFiles\mongodb>bin\mongo
  2. MongoDBshellversion:2.0.0
  3. connectingto:test
  4. >usetest;
  5. switchedtodbtest
  6. >map=function(){
  7. ...emit(this.name,{count:1});
  8. ...};
  9. function(){
  10. emit(this.name,{count:1});
  11. }
  12. >reduce=function(key,values){
  13. ...vartotal=0;
  14. ...varindex=0;
  15. ...for(vari=0;i<values.length;i++){
  16. ...total+=values[i].count;
  17. ...index=i;
  18. ...}
  19. ...return{count:total};
  20. ...};
  21. function(key,values){
  22. vartotal=0;
  23. varindex=0;
  24. for(vari=0;i<values.length;i++){
  25. total+=values[i].count;
  26. index=i;
  27. }
  28. return{count:total};
  29. }
  30. >db.person.mapReduce(map,reduce,{out:"resultCollection"});
  31. {
  32. "result":"resultCollection",
  33. "timeMillis":112,
  34. "counts":{
  35. "input":10,
  36. "emit":10,
  37. "reduce":2,
  38. "output":2
  39. },
  40. "ok":1,
  41. }
  42. >db.resultCollection.find();
  43. {"_id":"xiaofancn","value":{"count":3}}
  44. {"_id":"小樊","value":{"count":7}}

Java代码收藏代码
  1. map=function(){
  2. emit(this.name,{count:1});
  3. };

此函数是形成下面的key-values结构的,emit就是指定key和value的,也是结果的数据结构。

xiaofancn [{count:1},{count:1},{count:1}]

由于name字段为xiaofancn的person有三个,所以形成三个{count:1}数组。

Java代码收藏代码
  1. reduce=function(key,values){
  2. vartotal=0;
  3. for(vari=0;i<values.length;i++){
  4. total+=values[i].count;
  5. }
  6. return{count:total};
  7. };

reduce函数中参数key和map函数的emit指定的key(this.name)是同一个key(name),values就是map函数形成的values([{count:1},{count:1},{count:1}])

经过reduce函数处理就形成了key和一个最终的{count:3}数据结构。定义好的函数,需要MongoDB执行

Java代码收藏代码
  1. db.person.mapReduce(map,reduce,{out:"resultCollection"});
  2. db.resultCollection.find();

db代表当前的数据库,person当前的文档,mapReduce调用函数,out:是指定输出的文档名称。


好了,会使用Javascript,使用Java就是拼接我们的Javascript代码了。

Java代码收藏代码
  1. publicvoidMapReduce(){
  2. DBCollectionpersonColl=mongoOperations.getCollection(mongoOperations
  3. .getCollectionName(Person.class));
  4. Stringmap="function(){emit(this.name,{count:1});}";
  5. Stringreduce="function(key,values){";
  6. reduce=reduce+"vartotal=0;";
  7. reduce=reduce+"for(vari=0;i<values.length;i++){total+=values[i].count;}";
  8. reduce=reduce+"return{count:total};}";
  9. Stringresult="resultCollection";
  10. MapReduceOutputmapReduceOutput=personColl.mapReduce(map,
  11. reduce.toString(),result,null);
  12. DBCollectionresultColl=mapReduceOutput.getOutputCollection();
  13. DBCursorcursor=resultColl.find();
  14. while(cursor.hasNext()){
  15. System.out.println(cursor.next());
  16. }
  17. }

MapReduce是一个编程模型,封装了并行计算、容错、数据分布、负载均衡等细节问题。

输入是一个key-value对的集合,中间输出也是key-value对的集合,用户使用两个函数:Map和Reduce。

在使用MongoDb的mapreduce功能时,我找Java代码找半天,结果练了半天的Javascript代码。

MongoDb是通过解析“Javascript”代码来计算的。所有我们先用Javascript代码调通,再使用Java代码拼接使用这个MapReduce功能。

Java代码收藏代码
  1. db.runCommand(
  2. {
  3. mapreduce:<collection>,
  4. map:<mapfunction>,
  5. reduce:<reducefunction>
  6. [,query:<queryfilterobject>]
  7. [,sort:<sortthequery.usefuloptimization>]for
  8. [,limit:<numberofobjectstofromcollection>]return
  9. [,out:<output-collectionname>]
  10. [,keeptemp:<|>]truefalse
  11. [,finalize:<finalizefunction>]
  12. [,scope:<objectwherefieldsgointojavascriptglobalscope>]
  13. [,verbose:]true
  14. });

参数说明:

  • mapreduce: 要操作的目标集合。
  • map: 映射函数 (生成键值对序列,作为 reduce 函数参数)。
  • reduce: 统计函数。
  • query: 目标记录过滤。
  • sort: 目标记录排序。
  • limit: 限制目标记录数量。
  • out: 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
  • keeptemp: 是否保留临时集合。
  • finalize: 最终处理函数 (对 reduce 返回结果进行最终整理后存入结果集合)。
  • scope: 向 map、reduce、finalize 导入外部变量。
  • verbose: 显示详细的时间统计信息

先看看我们的文档结果


我使用上一篇文章插入数据http://xiaofancn.iteye.com/blog/1163200

讲讲我们要实现的功能,就是按照名字name统计记录个数。

Java代码收藏代码
  1. D:\ProgramFiles\mongodb>bin\mongo
  2. MongoDBshellversion:2.0.0
  3. connectingto:test
  4. >usetest;
  5. switchedtodbtest
  6. >map=function(){
  7. ...emit(this.name,{count:1});
  8. ...};
  9. function(){
  10. emit(this.name,{count:1});
  11. }
  12. >reduce=function(key,values){
  13. ...vartotal=0;
  14. ...varindex=0;
  15. ...for(vari=0;i<values.length;i++){
  16. ...total+=values[i].count;
  17. ...index=i;
  18. ...}
  19. ...return{count:total};
  20. ...};
  21. function(key,values){
  22. vartotal=0;
  23. varindex=0;
  24. for(vari=0;i<values.length;i++){
  25. total+=values[i].count;
  26. index=i;
  27. }
  28. return{count:total};
  29. }
  30. >db.person.mapReduce(map,reduce,{out:"resultCollection"});
  31. {
  32. "result":"resultCollection",
  33. "timeMillis":112,
  34. "counts":{
  35. "input":10,
  36. "emit":10,
  37. "reduce":2,
  38. "output":2
  39. },
  40. "ok":1,
  41. }
  42. >db.resultCollection.find();
  43. {"_id":"xiaofancn","value":{"count":3}}
  44. {"_id":"小樊","value":{"count":7}}

Java代码收藏代码
  1. map=function(){
  2. emit(this.name,{count:1});
  3. };

此函数是形成下面的key-values结构的,emit就是指定key和value的,也是结果的数据结构。

xiaofancn [{count:1},{count:1},{count:1}]

由于name字段为xiaofancn的person有三个,所以形成三个{count:1}数组。

Java代码收藏代码
  1. reduce=function(key,values){
  2. vartotal=0;
  3. for(vari=0;i<values.length;i++){
  4. total+=values[i].count;
  5. }
  6. return{count:total};
  7. };

reduce函数中参数key和map函数的emit指定的key(this.name)是同一个key(name),values就是map函数形成的values([{count:1},{count:1},{count:1}])

经过reduce函数处理就形成了key和一个最终的{count:3}数据结构。定义好的函数,需要MongoDB执行

Java代码收藏代码
  1. db.person.mapReduce(map,reduce,{out:"resultCollection"});
  2. db.resultCollection.find();

db代表当前的数据库,person当前的文档,mapReduce调用函数,out:是指定输出的文档名称。


好了,会使用Javascript,使用Java就是拼接我们的Javascript代码了。

Java代码收藏代码
  1. publicvoidMapReduce(){
  2. DBCollectionpersonColl=mongoOperations.getCollection(mongoOperations
  3. .getCollectionName(Person.class));
  4. Stringmap="function(){emit(this.name,{count:1});}";
  5. Stringreduce="function(key,values){";
  6. reduce=reduce+"vartotal=0;";
  7. reduce=reduce+"for(vari=0;i<values.length;i++){total+=values[i].count;}";
  8. reduce=reduce+"return{count:total};}";
  9. Stringresult="resultCollection";
  10. MapReduceOutputmapReduceOutput=personColl.mapReduce(map,
  11. reduce.toString(),result,null);
  12. DBCollectionresultColl=mapReduceOutput.getOutputCollection();
  13. DBCursorcursor=resultColl.find();
  14. while(cursor.hasNext()){
  15. System.out.println(cursor.next());
  16. }
  17. }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics