Couchdb 映射/减少Couchbase和;云雀

Couchdb 映射/减少Couchbase和;云雀,couchdb,mapreduce,cloudant,couchbase,Couchdb,Mapreduce,Cloudant,Couchbase,我一直在玩Couchbase服务器,现在刚刚尝试将我的本地db复制到Cloudant,但是我的map/reduce函数对在构建一组独特的标记及其关联项目时得到了相互冲突的结果 // map.js function(doc) { if (doc.tags) { for(var t in doc.tags) { emit(doc.tags[t], doc._id); } } } // reduce.js function(key,values,rereduce)

我一直在玩Couchbase服务器,现在刚刚尝试将我的本地db复制到Cloudant,但是我的map/reduce函数对在构建一组独特的标记及其关联项目时得到了相互冲突的结果

// map.js
function(doc) {
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], doc._id);
    }
  }
}

// reduce.js
function(key,values,rereduce) {
  if (!rereduce) {
    var res=[];
    for(var v in values) {
      res.push(values[v]);
    }
    return res;
  } else {
    return values.length;
  }
}
在Cloudbase server中,这将返回类似于以下内容的JSON:

{"rows":[
{"key":"3d","value":["project1","project3","project8","project10"]},
{"key":"agents","value":["project2"]},
{"key":"fabrication","value":["project3","project5"]}
]}
这正是我想要和期望的。但是,对Cloudant副本的相同查询将返回以下结果:

{"rows":[
{"key":"3d","value":4},
{"key":"agents","value":1},
{"key":"fabrication","value":2}
]}

所以它只返回值数组的长度。。。非常令人困惑&我感谢一些M&R忍者的见解……;)

看起来这正是给定reduce函数时所期望的行为。关键部分是:

else {
return values.length;
}

在Cloudant中,总是调用rereduce(因为reduce需要跨越多个碎片)。在这种情况下,rereduce调用values.length,它只返回数组的长度。

我更喜欢隐式地减少/重新减少,而不是依赖
rereduce
参数

function(doc) { // map
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], {id:doc._id, tag:doc.tags[t]});
    }
  }
}
然后reduce检查它是从相同的标记中累积文档ID,还是只是计算不同的标记

function(keys, vals, rereduce) {
  var initial_tag = vals[0].tag;

  return vals.reduce(function(state, val) {
    if(initial_tag && val.tag === initial_tag) {
      // Accumulate ids which produced this tag.
      var ids = state.ids;
      if(!ids)
        ids = [ state.id ]; // Build initial list from the state's id.
      return { tag: val.tag, 
             , ids: ids.concat([val.id])
             };
    } else {
      var state_count = state.ids ? state.ids.length : state;
      var val_count   = val.ids   ? val.ids.length   : val;
      return state_count + val_count;
    } 
  })
}
(我没有测试这段代码,但你明白了。只要
标记
的值相同,它是减少还是减少都无关紧要。一旦不同的标记开始一起减少,它就会检测到,因为
标记
的值将发生变化。因此在这一点上,就开始累积

我以前用过这个把戏,虽然在我看来不值得

同样在您的特定情况下,这是一个危险的reduce函数。您正在构建一个宽列表以查看所有带有标记的文档。CouchDB喜欢高列表,而不是胖列表。如果您希望查看所有带有标记的文档,您可以映射它们

for(var a = 0; a < doc.tags.length; a++) {
  emit(doc.tags[a], doc._id);
}

我明白了,但是我如何编写这个查询,使它在两个平台上产生相同的结果(#1)?我现在不在乎我的reduce函数是否完美,但我会假设一个一致的行为…+1,Alan.Toxi,我建议你重写,以便“闻到”re reduce vs.initial reduce,无需检查从Coach传递的参数。我之前已经这样做过,因此我将尝试作为实际答案,以获得更好的格式。您只需记住Cloudant始终调用rereduce,因此如果您希望两者保持一致,则需要rereduce子句与reduce子句匹配。附带说明:CouchDB中的任何重要reduce函数都将使用reduce,因此了解引擎盖下的力学是一个好主意。例如,我一直忽略生产中的reduce。我将在回答中向您展示。谢谢大家的见解!(很抱歉,我花了这么长时间才回复,被撤走)我已经设法解决了这个问题,但有时仍然发现在couchdb中没有任何调试功能的情况下很难完全解决reduce部分。能够看到中间结果将有助于更好地理解正在发生的事情。。。
{"total_rows":287,"offset":30,"rows":[
{"id":"project1","key":"3d","value":"project1"}
{"id":"project3","key":"3d","value":"project3"}
{"id":"project8","key":"3d","value":"project8"}
{"id":"project10","key":"3d","value":"project10"}
]}