javascript – MongoDB集合上的MapReduce变空了

我一直试图将许多大型数据集合到一个集合中,但是我在编写MapReduce函数时遇到了问题.

这就是我的数据的样子(这里有17行,实际上我有400万行):

{"user": 1, "day": 1, "type": "a", "sum": 10}
{"user": 1, "day": 2, "type": "a", "sum": 32}
{"user": 1, "day": 1, "type": "b", "sum": 11}
{"user": 2, "day": 4, "type": "b", "sum": 2}
{"user": 1, "day": 2, "type": "b", "sum": 1}
{"user": 1, "day": 3, "type": "b", "sum": 9}
{"user": 1, "day": 4, "type": "b", "sum": 12}
{"user": 2, "day": 2, "type": "a", "sum": 3}
{"user": 3, "day": 2, "type": "b", "sum": 81}
{"user": 1, "day": 4, "type": "a", "sum": 22}
{"user": 1, "day": 5, "type": "a", "sum": 39}
{"user": 2, "day": 5, "type": "a", "sum": 8}
{"user": 2, "day": 3, "type": "b", "sum": 1}
{"user": 3, "day": 3, "type": "b", "sum": 99}
{"user": 2, "day": 3, "type": "a", "sum": 5}
{"user": 1, "day": 3, "type": "a", "sum": 41}
{"user": 3, "day": 4, "type": "b", "sum": 106}
...  

我试图让它最终看起来像这样(每种类型的数组,其中的内容只是当天决定的相应索引中的总和,如果该类型不存在那一天,它只是0):

{"user": 1, "type_a_sums": [10, 32, 41, 22, 39], "type_b_sums": [11, 1, 9, 12, 0]}
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]}
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 81, 99, 106, 0]}
...

这是我一直在尝试的MapReduce:

var mapsum = function(){
    var output = {user: this.user, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: this.type, tempSum: this.sum, tempDay: this.day}

    if(this.type == "a") {
        output.type_a_sums[this.day-1] = this.sum;
    }

    if(this.type == "b") {
        output.type_b_sums[this.day-1] = this.sum;
    }

    emit(this.user, output);
};

var r = function(key, values) {
    var outs = {user: 0, type_a_sums: [0, 0, 0, 0, 0], type_b_sums: [0, 0, 0, 0, 0], tempType: -1, tempSum: -1, tempDay: -1}

    values.forEach(function(v){

        outs.user = v.user;

        if(v.tempType == "a") {
            outs.type_a_sums[v.tempDay-1] = v.tempSum;
        }

        if(v.tempType == "b") {
            outs.type_b_sums[v.tempDay-1] = v.tempSum;
        }

    });

    return outs;
};


res = db.sums.mapReduce(mapsum, r, {out: 'joined_sums'})

这给了我关于小样本的输出,但是当我运行它超过400万时,我得到了大量的输出,如下所示:

{"user": 1, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]}
{"user": 2, "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0]}
{"user": 3, "type_a_sums": [0, 0, 0, 0, 0], "type_b_sums": [0, 0, 0, 0, 0]}

在我填充实际函数之前,在其数组中应该有总和的大部分用户实际上只是填充了reduce函数out对象中的虚拟数组中的0.

真正奇怪的是,如果我在同一个集合上运行相同的功能,但只检查一个用户res = db.sums.mapReduce(mapsum,r,{query:{user:1},out:’joined_sums’})我知道应该在他们的数组中有总和,但之前一直在变为全0,我实际上将得到我想要的那个用户的输出.全部400万再次运行它我到处都是0.这就像它只是写了它对虚拟填充器阵列所做的所有工作.

我有太多数据吗?考虑到时间,它不应该能够通过它吗?还是我遇到了一些我不知道的障碍?

最佳答案 感谢您提供大量详细信息.这里有一些问题.

让我们从顶部开始吧.

I’m trying to get it to look like this in the end

{“user”: 2, “type_a_sums”: [0, 3, 5, 0, 8], “type_b_sums”: [0, 0, 1, 2, 0]}

它实际上看起来像这样:

{ _id: { "user": 2 }, value: { "type_a_sums": [0, 3, 5, 0, 8], "type_b_sums": [0, 0, 1, 2, 0] }

请注意,_id有点像你的“分组依据”,而且有点像你的“总和”列.

问题#1是你将用户作为你的钥匙,但它也是你价值的一部分.这不是必需的. reduce只会减少两个共享相同键的值,你也不需要这行:outs.user = v.user;

你也有问题#2:你的减少是不正确的.

I think it has to do with reduce() being called more than once per key.

reduce()的目标是多次调用它.它应该跨服务器扩展.因此,一台服务器可以调用reduce几次,这些结果可以合并并发送到另一台服务器.

这是一种不同的方式来看待它. Reduce接受一组值对象并将它们减少为单个值对象.

这里有一些推论:

>如果我确实减少([a,b]),它应该与reduce([b,a])相同.
>如果我确实减少([a,reduce([b,c]))它应该与reduce相同([reduce([a,b]),c])

因此,无论我运行它的顺序或值减少多少次都无关紧要,它始终是相同的输出.

如果你看看你的代码,这不是正在发生的事情.只需看一下type_a_sums.如果我将以下两个值减少会发生什么?

reduce([ [0,0,1,0,0], [0,2,0,0,0] ]) => ???

对我来说,这看起来像输出应该是[0,2,1,0,0].如果这是真的,那么您不需要所有这些temp_X字段.相反,您需要专注于发出正确的数组,然后正确合并这些数组.

点赞