映射/减少Couchbase和amp;之间的差异CloudAnt

时间:2011-05-18 22:31:05

标签: couchdb mapreduce cloudant couchbase

我一直在使用Couchbase Server,现在只是尝试将我的本地数据库复制到Cloudant,但是我的map / reduce函数对的结果出现了冲突,以构建一组带有相关项目的唯一标记... < / p>

// 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服务器中,它返回JSON,如:

{"rows":[
{"key":"3d","value":["project1","project3","project8","project10"]},
{"key":"agents","value":["project2"]},
{"key":"fabrication","value":["project3","project5"]}
]}

这正是我想要的&amp;预期。但是,Cloudant副本上的相同查询将返回:

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

所以它以某种方式只返回值数组的长度......非常混乱&amp;感谢一些M&amp; R ninjas的任何见解......;)

2 个答案:

答案 0 :(得分:4)

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

else {
return values.length;
}

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

答案 1 :(得分:2)

我更倾向于隐式减少/重新减少,而不是依赖于rereduce参数。

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

然后减少检查是否从相同的标记累积文档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;
    } 
  })
}

(我没有测试这段代码,但是你明白了。只要tag值相同,无关紧要是否为减少或减少一旦不同的标签开始一起减少,它会检测到因为tag值会发生变化。所以此时才开始累积。

我之前使用过这个技巧,虽然IMO很少值得。

同样在您的特定情况中,这是一个危险的减少功能。您正在构建一个宽列表以查看具有标记的所有文档。 CouchDB喜欢高级列表,而不是胖列表。如果您想查看所有带标记的文档,可以映射它们。

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

现在您可以查询/db/_design/app/_view/docs_by_tag?key="3d",您应该

{"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"}
]}