MongoDB mapReduce和Spring Data配合使用详解

来源:互联网 发布:空气曲棍球 淘宝 编辑:程序博客网 时间:2024/05/17 13:39
经过几天的折腾, 终于弄明白了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 : <query filter object>]  
  7.     [, sort : <sort the query.  useful   optimization>] for  
  8.     [, limit : <number of objects to   from collection>] return  
  9.     [, out : <output-collection name>]  
  10.     [, keeptemp: < | >] true false  
  11.     [, finalize : <finalizefunction>]  
  12.     [, scope : <object where fields go into javascript global scope >]  
  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:\Program Files\mongodb>bin\mongo  
  2. MongoDB shell version: 2.0.0  
  3. connecting to: test  
  4. > use test;  
  5. switched to db test  
  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. ... var total = 0;  
  14. ... var index =0;  
  15. ... for(var i=0;i<values.length;i++){  
  16. ...  total += values[i].count;  
  17. ...  index = i;  
  18. ... }  
  19. ... return {count:total};  
  20. ... };  
  21. function (key, values) {  
  22.     var total = 0;  
  23.     var index = 0;  
  24.     for (var i = 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.     var total = 0;  
  3.     for(var i=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. public void MapReduce() {  
  2.   
  3.         DBCollection personColl = mongoOperations.getCollection(mongoOperations  
  4.                 .getCollectionName(Person.class));  
  5.         String map = "function() { emit(this.name, {count:1});}";  
  6.           
  7.         String reduce = "function(key, values) {";  
  8.         reduce=reduce+"var total = 0;";  
  9.         reduce=reduce+"for(var i=0;i<values.length;i++){total += values[i].count;}";  
  10.         reduce=reduce+"return {count:total};}";  
  11.           
  12.         String result = "resultCollection";  
  13.           
  14.         MapReduceOutput mapReduceOutput = personColl.mapReduce(map,  
  15.                 reduce.toString(), result, null);  
  16.         DBCollection resultColl = mapReduceOutput.getOutputCollection();  
  17.         DBCursor cursor= resultColl.find();  
  18.         while (cursor.hasNext()) {  
  19.             System.out.println(cursor.next());  
  20.         }  
  21.     }  
 

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 : <query filter object>]  
  7.     [, sort : <sort the query.  useful   optimization>] for  
  8.     [, limit : <number of objects to   from collection>] return  
  9.     [, out : <output-collection name>]  
  10.     [, keeptemp: < | >] true false  
  11.     [, finalize : <finalizefunction>]  
  12.     [, scope : <object where fields go into javascript global scope >]  
  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:\Program Files\mongodb>bin\mongo  
  2. MongoDB shell version: 2.0.0  
  3. connecting to: test  
  4. > use test;  
  5. switched to db test  
  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. ... var total = 0;  
  14. ... var index =0;  
  15. ... for(var i=0;i<values.length;i++){  
  16. ...  total += values[i].count;  
  17. ...  index = i;  
  18. ... }  
  19. ... return {count:total};  
  20. ... };  
  21. function (key, values) {  
  22.     var total = 0;  
  23.     var index = 0;  
  24.     for (var i = 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.     var total = 0;  
  3.     for(var i=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. public void MapReduce() {  
  2.   
  3.         DBCollection personColl = mongoOperations.getCollection(mongoOperations  
  4.                 .getCollectionName(Person.class));  
  5.         String map = "function() { emit(this.name, {count:1});}";  
  6.           
  7.         String reduce = "function(key, values) {";  
  8.         reduce=reduce+"var total = 0;";  
  9.         reduce=reduce+"for(var i=0;i<values.length;i++){total += values[i].count;}";  
  10.         reduce=reduce+"return {count:total};}";  
  11.           
  12.         String result = "resultCollection";  
  13.           
  14.         MapReduceOutput mapReduceOutput = personColl.mapReduce(map,  
  15.                 reduce.toString(), result, null);  
  16.         DBCollection resultColl = mapReduceOutput.getOutputCollection();  
  17.         DBCursor cursor= resultColl.find();  
  18.         while (cursor.hasNext()) {  
  19.             System.out.println(cursor.next());  
  20.         }  
  21.     }  
 
原创粉丝点击