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

Mapreduce 映射/减少以获取按键分组的每个文档的计数和最新日期,mapreduce,couchbase,Mapreduce,Couchbase,我的文档的简单版本如下所示: 文件: 我想按键对文档进行分组,以获取每个键的最新日期和文档数,例如 { "Last": "2014-04-16T16:00:00", "Count": 10 } 我的想法是将“映射/减少视图和查询”设置组设置为true。 这就是我迄今为止所尝试的。我知道确切的数字,但不是正确的日期 地图 减少 函数(键、值、返回值){ var结果={ 最后:0,, 计数:0 }; 如果(减少){ 对于(变量i=0;iresult.Last?值[i].Last:result.La

我的文档的简单版本如下所示:

文件:

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

{ "Last": "2014-04-16T16:00:00", "Count": 10 }
我的想法是将“映射/减少视图和查询”设置组设置为true。
这就是我迄今为止所尝试的。我知道确切的数字,但不是正确的日期

地图 减少
函数(键、值、返回值){
var结果={
最后:0,,
计数:0
};
如果(减少){
对于(变量i=0;i
您没有比较日期。。。Couchbase按键对值进行排序。在您的情况下,它不会按日期排序,因此您应该在reduce函数中手动进行排序。可能会是这样的:

result.Last=值[i]。Last>result.Last?值[i].Last:result.Last;

在reduce函数中,它也可以是数组,所以我不认为reduce函数总是正确的

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

函数(k,v,r){
if(r){
如果(v.长度>1){
var m=v[0]。日期;
var-mid=0;
对于(var i=1;i m){
m=v[i]。日期;
mid=i;
}
}
返回v[mid];
}
否则{
返回v[0]| | v;
}
}
如果(v.长度>1){
var m=v[0]。日期;
var-mid=0;
对于(var i=1;i m){
m=v[i]。日期;
mid=i;
}
}
返回v[mid];
}
否则{
返回v[0]| | v;
}
}

UPD:以下是reduce的一个示例: 该函数的输入日期(值)如下所示(我只使用了数字而不是文本日期来缩短它):

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

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

对象{Date:8}

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

然后在下一步中(如果集群或“分支”中有多台机器),将调用
rereduce
,并且
rereduce
var将设置为
true

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

因此,我们需要对新值进行完全相同的处理,以找到最大值

从评论中回答您的问题:我不记得为什么我在reduce和rereduce中使用相同的代码,因为那是很久以前的事了(couchbase 2.0在dev preview中的时候)。可能couchbase有一些bug,或者我只是想了解rereduce是如何工作的。但是我记得,如果没有这个
if(r){..}
它在那个时候就不起作用了


您可以尝试放置
返回v在my或您的reduce函数的不同部分中编码,以查看它在每个reduce阶段返回的内容。最好自己尝试一次,以了解那里实际发生的情况。

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

处理此问题的另一种方法是在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});
  }
}

我发现这很简单,在我的情况下就可以了。

你不是在比较日期。。。Couchbase按键对值进行排序。在您的情况下,它不会按日期排序,因此您应该在reduce函数中手动执行。谢谢。我将测试您的代码,但您在REREREDUCE/not REREREDUCE部分使用相同的代码?有什么原因吗?你能解释一下吗?@agstudy我已经更新了我的答案,如果你还有更多问题,尽管问。谢谢你的解释(+1)。我将发布一个与你完全不同的答案。我是couchbase的新手,所以我不确定我是否正确使用了它,所以我需要一些反馈。@agstudy,正如我刚刚写的,尝试放置return v;在reduce函数的不同部分编写代码,以便自己发现它。你也可以阅读这篇文章:这篇文章可能也会很有用。谢谢你的链接。我已经读过了。但我认为它只使用内置的reduce函数。不是吗?
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;
}
{
   "date": "2014-04-16T17:13:00",
   "key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
   "message": "message1",
}

{
   "date": "2014-04-16T15:22:00",
   "key": "de5cefc56ff51c33351459b88d42ca9f828445c0",
   "message": "message2",
}
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});
  }
}