我正在尝试在用于生产的Mongo 2.4版数据库中找到重复项,因此无法更新。由于2.4中不存在聚合,我无法使用聚合管道来查找重复项,因此我尝试使用MapReduce找到解决方案。
我已经通过MongoVUE的Map Reduce界面尝试了以下一组map,reduce和finalize函数,并且在3,000,000条记录集合上运行不到一秒之后它们没有返回任何内容,这些集合肯定有重复的指示字段。显然出现了问题,但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
个记录。
答案 0 :(得分:1)
您的map-reduce代码在没有任何问题的情况下工作,但对于非常小的数据集。我认为reduce函数中的return values[0];
将是一个复制粘贴错误。您可以通过mongo shell尝试相同的操作。
由于2.4中不存在聚合,我无法使用聚合管道查找重复项,因此我试图找到解决方案 使用MapReduce。
你在这里弄错了,db.collection.aggregate(pipeline, options)
中引入了version 2.2
。
以下是如何使用aggregation
框架完成的,但由于您的数据集非常庞大,并且$sort
运算符的内存限制为RAM的10%,因此不会优先使用它。 V2.4。
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"});
运行map-reduce,
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
功能不过滤掉键。因此,您只能获得重复的密钥。您将获得map-reduce输出中的所有键。在最终确定功能中,您可以不显示其值,这就是您正在做的事情。