我正在尝试了解map / reduce的行为。
这是地图功能:
function() {
var klass = this.error_class;
emit('klass', { model : klass, count : 1 });
}
还原功能:
function(key, values) {
var results = { count : 0, klass: { foo: 'bar' } };
values.forEach(function(value) {
results.count += value.count;
results.klass[value.model] = 0;
printjson(results);
});
return results;
}
然后我运行它:
{
"count" : 85,
"klass" : {
"foo" : "bar",
"Twitter::Error::BadRequest" : 0
}
}
{
"count" : 86,
"klass" : {
"foo" : "bar",
"Twitter::Error::BadRequest" : 0,
"Stream:DirectMessage" : 0
}
}
在这一点上,一切都很好,但是这里每100个文件都会产生读取锁:
{
"count" : 100,
"klass" : {
"foo" : "bar",
"Twitter::Error::BadRequest" : 0,
"Stream:DirectMessage" : 0
}
}
{ "count" : 100, "klass" : { "foo" : "bar", "undefined" : 0 } }
我保留了我的密钥foo
,并且我的count
属性不断增加。问题是其他一切都成了undefined
。
那么,为什么我的count
属性仍然不错时,我的对象会丢失动态键?
答案 0 :(得分:0)
要记住你的reduce函数的一点是传递给它的值要么是map函数的输出,要么是之前调用reduce的返回值。
这是关键 - 它意味着可以将数据的部分映射/减少到不同的机器(例如mongo集群的不同分片),然后再次使用以重新组装数据。这也意味着mongo不必首先映射每个值,将所有结果保存在内存中,然后将它们全部减少:它可以映射和减少块,在必要时重新减少。
换句话说,必须符合以下条件:
reduce(k,[A,B,C]) == reduce(k, [A, reduce(k,[A,B]))
你的reduce函数的输出没有model
属性,所以如果它在重新减少中使用,那么这些未定义的值将会出现。
您需要让reduce函数返回类似于map函数发出的格式,以便您可以无差别地处理这两者(通常是最简单的),或者以不同方式处理重新缩减的值。