我试图在用于生产的Mongo 2.4版本数据库中找到重复的数据库,因此无法更新。由于2.4中不存在聚合,我无法使用聚合管道来查找重复项,因此我正在尝试使用MapReduce找到解决方案。
我已经通过MongoVUE的map reduce接口尝试了以下一组map、reduce和finalize函数,但它们在3000000个记录集合上运行不到一秒钟后就没有返回任何结果,该集合在指示字段上肯定有重复项。显然出了问题,但MongoVUE没有显示任何错误消息或有用的指示。
function Map() {
emit(
{name: this.name, LocationId: this.LocationId,
version: this.version},
{count:1, ScrapeDate: this.ScrapeDate}
);
}
function Reduce(key, values) {
var reduced = {count:0, ScrapeDate:''2000-01-01''};
values.forEach(function(val) {
reduced.count += val.count;
if (reduced.ScrapeDate.localeCompare(val.ScrapeDate) < 0)
reduced.ScrapeDate=val.ScrapeDate;
});
return reduced;
return values[0];
}
function Finalize(key, reduced) {
if (reduced.count > 1)
return reduced;
}
我只需要找到共享相同name
、LocationId
和version
的多个记录的任何实例,并理想地显示此类记录的最新ScrapeDate
。
您的map reduce代码工作时没有任何问题,尽管它适用于非常小的数据集。我认为reduce函数中的return values[0];
将是复制粘贴错误。你可以通过mongo shell尝试同样的方法。
由于聚合在2.4中不存在,我无法使用聚合管道来查找重复项,因此我正在尝试找到解决方案使用MapReduce
你错了,db.collection.aggregate(pipeline, options)
是在version 2.2
中引入的。
以下是使用aggregation
框架的方法,但这不是首选方法,因为您的数据集非常庞大,并且在v2.4中,$sort
运算符的内存限制为RAM的10%。
db.collection.aggregate(
[
// sort the records, based on the 'ScrapeDate' field, in descending order.
{$sort:{"ScrapeDate":-1}},
// group by the key fields, and take the 'ScrapeDate' of the first document,
// Since it is in sorted order, the first document would contain the
// highest field value.
{$group:{"_id":{"name":"$name","LocationId":"$LocationId","version":"$version"}
,"ScrapeDate":{$first:"$ScrapeDate"}
,"count":{$sum:1}}
},
// output only the group, having documents greater than 1.
{$match:{"count":{$gt:1}}}
]
);
谈到Map reduce函数,它在我的测试数据上运行时没有出现问题。
db.collection.insert({"name":"c","LocationId":1,"version":1,"ScrapeDate":"2000-01-01"});
db.collection.insert({"name":"c","LocationId":1,"version":1,"ScrapeDate":"2001-01-01"});
db.collection.insert({"name":"c","LocationId":1,"version":1,"ScrapeDate":"2002-01-01"});
db.collection.insert({"name":"d","LocationId":1,"version":1,"ScrapeDate":"2002-01-01"});
运行地图缩减,
db.collection.mapReduce(Map,Reduce,{out:{"inline":1},finalize:Finalize});
o/p:
{
"results" : [
{
"_id" : {
"name" : "c",
"LocationId" : 1,
"version" : 1
},
"value" : {
"count" : 3,
"ScrapeDate" : "2002-01-01"
}
},
{
"_id" : {
"name" : "d",
"LocationId" : 1,
"version" : 1
},
"value" : null
}
],
"timeMillis" : 0,
"counts" : {
"input" : 4,
"emit" : 4,
"reduce" : 1,
"output" : 2
},
"ok" : 1,
}
请注意,输出包含一条没有任何重复项的记录的value:null
。
这是由于您的finalize
功能:
function Finalize(key, reduced) {
if (reduced.count > 1)
return reduced; // returned null by default for keys with single value,
// i.e count=1
}
finalize
函数不过滤按键。所以你不能只得到重复的密钥。你会得到所有的关键点,在地图上减少输出。在您的finalize函数中,您可以不显示它们的值,这就是您正在做的。