映射/缩小以获取按键分组的每个文档的计数和最新日期

时间:2014-04-16 17:03:55

标签: mapreduce couchbase

我的文档文档的简单版本是以下结构:

doc:

{
   "date": "2014-04-16T17:13:00",
   "key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
}

我想按密钥对文档进行分组,以获取每个密钥的最新日期和文档数量,例如

{ "Last": "2014-04-16T16:00:00", "Count": 10 }

我的想法是将地图/缩小视图和查询设置组设为真 这是我到目前为止所尝试的。我得到了确切的计数,但没有正确的日期。

地图

function (doc, meta) {
  if(doc.type =="doc")
      emit(doc.key, doc.date);
}

减少

function(key, values, rereduce) {
   var result = {
    Last: 0,
    Count: 0
  };

   if (rereduce) {
       for (var i = 0; i < values.length; i++) {
           result.Count += values[i].Count;
           result.Last = values[i].Last;
         }

   } else {
       result.Count = values.length;
       result.Last = values[0]
   }
  return result;
}

2 个答案:

答案 0 :(得分:2)

您没有比较日期... Couchbase按键对值进行排序。在您的情况下,它不会按日期排序,因此您应该在reduce函数中手动执行此操作。可能它看起来像: result.Last = values[i].Last > result.Last ? values[i].Last : result.Last;

并且在reduce函数中它也可以是一个数组,所以我不认为你的reduce函数总是正确的。

这是我的reduce函数的一个示例,它过滤文档并只保留一个具有最新日期的文档。可能它会有所帮助,或者你可以尝试使用它(看起来它看起来像你想要的reduce函数,你只需要在某处添加计数)。

function(k,v,r){ if (r){ if (v.length > 1){ var m = v[0].Date; var mid = 0; for (var i=1;i<v.length;i++){ if (v[i].Date > m){ m = v[i].Date; mid = i; } } return v[mid]; } else { return v[0] || v; } } if (v.length > 1){ var m = v[0].Date; var mid = 0; for (var i=1;i<v.length;i++){ if (v[i].Date > m){ m = v[i].Date; mid = i; } } return v[mid]; } else { return v[0] || v; } }

UPD:这是一个减少的例子: 该函数的输入日期(值)看起来像(我只使用数字而不是文本日期来缩短它):

[{Date:1},{Date:3},{Date:8},{Date:2},{Date:4},{Date:7},{Date:5}]

第一步rereduce将是false,所以我们需要在数组中找到最大的日期,它将返回

Object {Date: 8}

请注意,此函数可以调用一次,但可以在集群中的多个服务器上调用,也可以在一个couchbase实例内的b-tree的多个分支上调用。

然后在下一步(如果群集中有多台计算机或#34;分支&#34;)rereduce将被调用,rereduce var将设置为true < / p>

传入的数据将是: [{Date:8},{Date:10},{Date:3}],其中{Date:8}来自一个服务器(或分支),而其他日期来自另一个服务器(或分支)。

所以我们需要在新值上做同样的事情才能找到最大值。

从评论中回答你的问题:我不记得为什么我使用相同的代码进行reduce和rereduce,因为它很久以前(当couchbase 2.0处于开发预览版时)。可能是沙发基有一些错误,或者我只是想了解rereduce是如何工作的。但我记得没有那个if (r) {..}它当时没有用。

您可以尝试将return v;代码放在我或您的reduce函数的不同部分,以查看它在每个reduce阶段返回的内容。最好自己尝试一次,以了解那里发生的事情。

答案 1 :(得分:1)

我忘记提到我有相同密钥的许多文档。事实上,对于每个键,我可以有很多文档(此处有消息):

{
   "date": "2014-04-16T17:13:00",
   "key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
   "message": "message1",
}

{
   "date": "2014-04-16T15:22:00",
   "key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
   "message": "message2",
}

解决问题的另一种方法是在map函数中执行此操作:

function (doc, meta) {
  var count = 0;
  var last =''
  if(doc.type =="doc"){
    for (k in doc.message){
      count += 1; 
      last = doc.date> last?doc.date:last;
    }
    emit(doc.key,{'Count':count,'Last': last});
  }
}

我发现这个更简单,它可以完成我的工作。