下面的例子是在小数据下测试的,我尝试在单机的千万级别测试,等很久都没结果...
数据有表:crawler.videos,表结构是: _id, playUrl, siteId...
只有_id是有索引的,siteId不同的值分别代表不同的网站。值有:1,2,3三个值。
现在要统计数据库中每个网站的所含有的id数。就是相当于在mySql中select count(_id),siteId from videos group by siteId 的语句。
以siteId分组,统计各siteId所含有的id数。在mongo中,可以通过group函数来做,也可以通过mapReduce来做,现记录两种做法:
通过group()函数
语法:
db.coll.group(
{key: { fieldToGroup : true
},
cond: { condition_where },
reduce: function(obj , prev) { logical_sentenct; },
initial: { initial_values }
});
对于上述的需求,可以这样写:
use crawler;
db.videos.group(
{key:{siteId:true},
reduce:function(obj,prev){ prev.count++;},
initial:{count:0}
});
现在说明一下:因为需求中没条件限制,所以cond域就不用写了。另外在reduce中,那个function函数可以提出外面写,如:
r = function(obj,prev){
prev.count++};
db.videos.group(
{key:{siteId:true},
reduce: r,
initial:{count:0}
});
在mongoDB中,function()就相当于JavaScript的语法。
这里需要注意的是,在reduce的function函数中,一定要有两个参数(obj,prev),obj是当前遍历的对象,
prev是聚合计数器[aggregation counter obj]。
上述命令的结果显示是:
[
{
"siteId" : 1,
"count" : 188603
},
{
"siteId" : 3,
"count" : 2198
},
{
"siteId" : 2,
"count" : 210
}
]
通过MapReduce方法:
在mongo终端输入:
m = function () {
emit(this.siteId, 1);
};
r = function (key, values) {
var total = 0;
for (var i = 0; i < values.length; i++) {
total += values[i];
}
return total;
};
res = db.videos.mapReduce(m,r);
db[res.result].find(); //显示结果
上述的函数显示每个siteId的总记录数,结果如下:
{ "_id" : 1, "value" : 188603 }
{ "_id" : 2, "value" : 210 }
{ "_id" : 3, "value" : 2198 }
res = db.videos.mapReduce(m,r); 语句也可以这样写:
res = db.runCommand({
mapreduce:"videos",
map:m,
reduce:r});
若忘记把db.runCommand()的结果传入res中,则可以在运行完runCommand命令的打印信息里找到
"result" : "tmp.mr.mapreduce_1291273572_8",之类的信息,则表明结果保存在
tmp.mr.mapreduce_1291273572_8的表中,在终端直接写:
tmp.mr.mapreduce_1291273572_8.find()则会显示结果。
最后db[res.result].drop(),把最后结果删除。
Map函数中需要把emit()函数把结果传给reduce函数。emit(key,value)中,key是value作为分组的key,
value的类型需要和reduce函数的values的类型一致。Map函数在传给Reduce函数前,会合并相同key的value,
形成(key,values)的中间结果,并传给reduce函数。
Reduce函数中对中间结果进行处理,并把最后结果存入result中。
在mapReduce中可以添加条件,如db.videos.mapReduce(m,r[,option...]) 或根据官方文档的标准语法:
db.runCommand(
{ mapreduce : <collection>,
map : <mapfunction>,
reduce : <reducefunction>
[, query : <query filter object>]
[, sort : <sort the query. useful for
optimization>]
[, limit : <number of objects to return
from collection>]
[, out : <output-collection name>]
[, outType : ("normal"
|"merge"
|"reduce"
)] -- since 1.7.3
[, keeptemp: <true
|false
>]
[, finalize : <finalizefunction>]
[, scope : <object where fields go into javascript global scope >]
[, verbose : true
]
}
);