CouchDB特有的Map / Reduce结果

时间:2011-06-24 13:41:42

标签: nosql couchdb mapreduce

我一直在使用CouchDB很长一段时间没有任何问题。到现在为止。我最近在地图中看到了一些内容/缩小了我忽略的结果!

这是在“avgs”变量上执行sum之前。我基本上试图找到与特定键有关的所有值的平均值。没有什么花哨。结果如预期。

注意时间戳1308474660000的结果(表中的第4行): Before summing avgs


现在我sum“avgs”数组。现在这里有一个结果特有的东西。时间戳为1308474660000的密钥总和为null !!为什么CouchDB会为简单的null吐出sum个?我尝试使用自定义添加功能和同样的问题。

enter image description here 有人可以向我解释为什么我的map / reduce结果会出现这个问题吗?

CouchDB版本:1.0.1


更新

执行rereduce后,我得到一个reduce overflow错误!

Error: reduce_overflow_error

Reduce output must shrink more rapidly: Current output: '["001,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,101,1,1,1,1,1,1,11,1,1,1,1'... (first 100 of 396 bytes)

这是我修改过的reduce函数:

function (key, values, rereduce) {
  if(!rereduce) {
    var avgs = [];
    for(var i=values.length-1; i>=0 ; i--) {
      avgs.push(Number(values[i][0])/Number(values[i][1]));
    }
    return avgs;
  } else {
    return sum(values);
  };
}

更新2:

现在情况变得更糟了。它有选择地重新减少。此外,它已被归还的那些显示错误的结果。时间戳(1308474660000)的第4行中的值的长度应为2而不是3.

enter image description here

更新3:

我终于开始工作了。我没有正确理解rereduce的具体细节。 AFAIK,Couchdb本身决定如何/何时重新减少。在这个例子中,只要数组足够长就可以处理,Couchdb会将它发送到rereduce。所以我基本上不得不sum两次。一旦进入减少,再次进行减少。

function (key, values, rereduce) {
  if(!rereduce) {
    var avgs = [];
    for(var i=values.length-1; i>=0 ; i--) {
      avgs.push(Number(values[i][0])/Number(values[i][1]));
    }
    return sum(avgs);
  } else {
    return sum(values); //If my understanding of rereduce is correct, it only receives only the avgs that are large enough to not be processed by reduce.
  }
}

3 个答案:

答案 0 :(得分:2)

reduce函数中的for循环可能没有按照您的想法执行。例如,它可能会抛出您没想到的异常。

您期待一组2元组:

// Expectation
values = [ [value1, total1]
         , [value2, total2]
         , [value3, total3]
         ];

在重新缩减期间,该函数将在之前获得旧结果。

// Re-reduce values
values = [ avg1
         , avg2
         , avg3
         ]

因此,我将首先检查代码如何在rereduce为真时运行。也许一些简单的东西会解决它(虽然我经常需要log()个东西才能找到问题。)

function(keys, values, rereduce) {
  if(rereduce)
     return sum(values);

  // ... then the same code as before.
}

答案 1 :(得分:1)

我会详细说明我的点数/总和评论,以防你好奇。

此代码未经过测试,但希望您能得到这个想法。最终结果始终是一个简单的对象{"count":C, "sum":S},您可以通过计算S / C来了解平均值。

function (key, values, rereduce) {
  // Reduce function
  var count = 0;
  var sum = 0;
  var i;

  if(!rereduce) {
    // `values` stores actual map output
    for(i = 0; i < values.length; i++) {
      count += Number(values[i][1]);
      sum += Number(values[i][0]);
    }

    return {"count":count, "sum":sum};
  }

  else {
    // `values` stores count/sum objects returned previously.
    for(i = 0; i < values.length; i++) {
      count += values[i].count;
      sum   += values[i].sum;
    }

    return {"count":count, "sum":sum};
  }
}

答案 2 :(得分:0)

我使用以下代码进行平均。希望它有所帮助。

function (key, values) {
    return sum(values)/values.length;    
}