mongo java mapreduce_mongoDB实现MapReduce

一、MongoDB Map Reduce

Map-Reduce是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。

基本语法:

db.collection.mapReduce(

function() {emit(key,value);},//map 函数

function(key,values) {return reduceFunction}, //reduce 函数

{out: collection,

query: document,

sort: document,

limit: number

}

)

使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数,Map 函数调用 emit(key, value), 遍历 collection 中所有的记录, 将 key 与 value 传递给 Reduce 函数进行处理。

Map 函数必须调用 emit(key, value) 返回键值对。

参数说明:

map :映射函数 (生成键值对序列,作为 reduce 函数参数)。

reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。

out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。

query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)

sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制

limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)

二、示例

我们通过下面的一个例子来理解上面的概念

mongodb的student集合中存在以下数据:

/*1*/

{"_id":ObjectId("5c735e26b21aeac107319873"),

"stu_name" : "张三",

"course" : "英语",

"score" : 70,

"level" : "C"}

/*2*/

{"_id":ObjectId("5c735e26b21aeac107319874"),

"stu_name" : "张三",

"course" : "数学",

"score" : 95,

"level" : "A"}

/*3*/

{"_id":ObjectId("5c735e26b21aeac107319875"),

"stu_name" : "张三",

"course" : "语文",

"score" : 91,

"level" : "A"}

/*4*/

{"_id":ObjectId("5c735e26b21aeac107319876"),

"stu_name" : "张三",

"course" : "历史",

"score" : 98,

"level" : "A"}

/*5*/

{"_id":ObjectId("5c735e26b21aeac107319877"),

"stu_name" : "李四",

"course" : "数学",

"score" : 88,

"level" : "B"}

/*6*/

{"_id":ObjectId("5c735e26b21aeac107319878"),

"stu_name" : "李四",

"course" : "英语",

"score" : 93,

"level" : "A"}

/*7*/

{"_id":ObjectId("5c735e26b21aeac107319879"),

"stu_name" : "李四",

"course" : "语文",

"score" : 99,

"level" : "A"}

要求:统计出每个学生的level为A的成绩的总和,并按学生名字进行分组显示

其执行的逻辑过程如下图所示:

e17040a45eacddd4c63db1f54daf43ee.png

在mongo shell里面执行:

db.student.mapReduce(

function() { emit(this.stu_name,this.score); },

function(key, values) {returnArray.sum(values)},

{

query:{level:"A"},

out:"total_score"}

)

/*1*/

{"result":"total_score",

"timeMillis" : 171.0,

"counts" : {

"input" : 5,

"emit" : 5,

"reduce" : 2,

"output" : 2},

"ok" : 1.0}

结果表明,共有 5 个符合查询条件("level":"A")的student, 在map函数中生成了 5 个键值对文档,最后使用reduce函数将相同的键值分为 2 组。

具体参数说明:

result:储存结果的collection的名字,这是个临时集合,MapReduce的连接关闭后自动就被删除了。

timeMillis:执行花费的时间,毫秒为单位

input:满足条件被发送到map函数的文档个数

emit:在map函数中emit被调用的次数,也就是所有集合中的数据总量

ouput:结果集合中的文档个数(count对调试非常有帮助)

ok:是否成功,成功为1

err:如果失败,这里可以有失败原因,不过从经验上来看,原因比较模糊,作用不大

查看真正的统计结果:

078e73480cb828487e6c3cb22fc4e142.png

三、用spring-boot-starter-data-mongodb来实现上面的操作

1、新建maven工程:mongo-mapreduce

df6531e1eae4ff25c0a6714e8599a1f1.png

引入springboot依赖和mongodb依赖

4.0.0

com.mongo.mapreduce

mongo-mapreduce

1.0-SNAPSHOT

org.springframework.boot

spring-boot-starter-parent

1.4.1.RELEASE

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-data-mongodb

spring-boot-starter-logging

org.springframework.boot

2、创建配置文件application.yml,map函数:map.js,reduce函数:reduce.js

server:port: 8084context-path: /spring:data:mongodb:uri: mongodb://admin:admin@172.16.1.11:27017,172.16.1.11:27018/testdb?AutoConnectRetry=true

map.js

function() {

emit(this.stu_name,this.score);

}

reduce.js

function(key,values) {var sum = 0;for (var i = 0; i < values.length; i++)

sum+=values[i];returnsum;

}

3、创建springboot启动主类

packagecom.mongo.mapreduce;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/***@authorAdministrator

* @date 2019/02/25*/@SpringBootApplicationpublic classApplication {public static voidmain(String[] args){

SpringApplication.run(Application.class, args);

}

}

4、创建接收mapreduce结果的实体类

packagecom.mongo.mapreduce.model;/***@authorAdministrator

* @date 2019/02/25*/

public classMapReduceResult {privateString id;privateInteger value;publicString getId() {returnid;

}public voidsetId(String id) {this.id =id;

}publicInteger getValue() {returnvalue;

}public voidsetValue(Integer value) {this.value =value;

}

}

5、创建controller

packagecom.mongo.mapreduce.controller;importcom.mongo.mapreduce.model.MapReduceResult;importcom.sun.beans.decoder.ValueObject;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.mongodb.core.MongoTemplate;importorg.springframework.data.mongodb.core.mapreduce.MapReduceOptions;importorg.springframework.data.mongodb.core.mapreduce.MapReduceResults;importorg.springframework.data.mongodb.core.query.Criteria;importorg.springframework.data.mongodb.core.query.Query;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestMethod;importorg.springframework.web.bind.annotation.RestController;importjava.util.List;/***@authorAdministrator

* @date 2019/02/25*/@RestController

@RequestMapping("/map-reduce")public classTestController {

@AutowiredprivateMongoTemplate mongoTemplate;

@RequestMapping(value= "/result",method =RequestMethod.GET)public voidpostTest(){//删除_id不等于空的数据,等于删除所有数据,目的是清空上一次mapreduce的结果

Criteria criteria=new Criteria("_id");

criteria.ne("");

Query query= newQuery(criteria);

mongoTemplate.remove(query,"total_score");//执行map reduce操作

Criteria criteria1=new Criteria("level");

criteria1.is("A");

Query query1= newQuery(criteria1);

MapReduceOptions options=MapReduceOptions.options();

options.outputCollection("total_score");

options.outputTypeReduce();

MapReduceResults reduceResults =mongoTemplate.mapReduce(query1,"student","classpath:map.js","classpath:reduce.js",

options,

MapReduceResult.class);for(MapReduceResult reduceResult:reduceResults){

System.out.println("map reduce的结果如下:=========");

System.out.println("姓名:"+reduceResult.getId()+",A的总分:"+reduceResult.getValue());

}

}

}

6、用postman调用

cdb54533a4a9728f391e3a70906d3576.png

d7dccfa699870b6acc8f4076a970eb83.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值