Ruby on rails Mongoid MapReduce给出递归reduce函数的不规则结果
我有一个Ruby on rails Mongoid MapReduce给出递归reduce函数的不规则结果,ruby-on-rails,mongodb,mapreduce,mongoid,Ruby On Rails,Mongodb,Mapreduce,Mongoid,我有一个项目模型,它有一个属性类别。我希望项目计数按类别分组。我为这个功能写了一个MapReduce。它工作得很好。我最近写了一个脚本来创建5000个项目。现在我意识到我的map reduce只给出最后80条记录的结果。以下是mapreduce函数的代码 map = %Q{ function(){ emit({},{category: this.category}); } } reduce = %Q{ function(key, values){ var categ
项目
模型,它有一个属性类别
。我希望项目计数按类别分组。我为这个功能写了一个MapReduce。它工作得很好。我最近写了一个脚本来创建5000个项目。现在我意识到我的map reduce只给出最后80条记录的结果。以下是mapreduce函数的代码
map = %Q{
function(){
emit({},{category: this.category});
}
}
reduce = %Q{
function(key, values){
var category_count = {};
values.forEach(function(value){
if(category_count.hasOwnProperty(value.category))
category_count[value.category]++;
else
category_count[value.category] = 1
})
return category_count;
}
}
Item.map_reduce(map,reduce).out(inline: true).first.try(:[],"value")
经过研究,我发现。如何实现我想要的功能 我同意尼尔·伦的评论 从提供的信息中我可以看到,如果您使用的MongoDB版本大于或等于2.2,那么可以使用聚合框架而不是map reduce
db.items.aggregate([
{ $group: { _id: '$category', category_count: { $sum: 1 } }
])
在MongoDB()中编写map reduce代码时,必须遵循一条规则。一个是emit(它发出键/值对)必须与reduce函数返回的值具有相同的格式 如果
emit(this.key,this.value)
则reduce必须返回与this.value
完全相同的类型。如果emit({},1)
则reduce必须返回一个数字。如果emit({},{category:this.category})
则reduce必须返回格式为{category:“string”}
(假设category是字符串)的文档
所以这显然不是你想要的,因为你想要的是总数,所以让我们看看reduce返回了什么,并从中计算出你应该排放什么
最后,您似乎希望累积一个文档,其中每个类别都有一个键名,其值是一个表示其出现次数的数字。比如:
{category_name1:total, category_name2:total}
如果是这种情况,那么正确的映射函数将emit({},{“this.category”:1})
,在这种情况下,reduce将需要为每个类别对应的键添加数字
以下是地图的外观:
map=function (){
category = { };
category[this.category]=1;
emit({},category);
}
下面是正确的相应减少:
reduce=function (key,values) {
var category_count = {};
values.forEach(function(value){
for (cat in value) {
if( !category_count.hasOwnProperty(cat) ) category_count[cat]=0;
category_count[cat] += value[cat];
}
});
return category_count;
}
请注意,它满足-如果从不调用reduce函数,它将正常工作(如果集合中只有一个文档,则会出现这种情况),如果reduce函数被多次调用,它将正常工作(当您有100多个文档时会发生这种情况)
一种更为传统的方法是将category name作为键,将number作为值。这简化了映射并减少了:
map=function() {
emit(this.category, 1);
}
reduce=function(key,values) {
var count=0;
values.forEach(function(val) {
count+=val;
}
return count;
}
这将合计每个类别出现的次数。这也满足了MapReduce的要求——如果从不调用reduce函数,它将正常工作(对于只出现一次的任何类别都是如此),如果reduce函数被多次调用,它将正常工作(如果任何类别出现超过100次,则会发生这种情况)
正如其他人所指出的,聚合框架使相同的工作变得更加简单:
db.collection.aggregate({$group:{_id:"$category",count:{$sum:1}}})
尽管这与我展示的第二个mapReduce的格式相匹配,而不是您原来的格式,即将类别名称作为键输出。然而。也许你们的头脑中并没有得到足够的关注,但这个问题在输入文档和期望结果方面也缺乏足够的细节,以便得到回答。没有人回答,因为没有足够的细节来回答。你现在没有累积接近票数的唯一原因是因为你提供了悬赏。用细节编辑你们的问题,以便得到答案。有足够的细节可以回答——我在我的答案中说明他做错了什么,如何正确地做,以及有什么更好的方法来做。