2

我一直在玩 Couchbase Server,现在只是尝试将我的本地数据库复制到 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 服务器中,这将返回 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 ninjas 的任何见解......;)

4

2 回答 2

4

看起来这正是您在 reduce 函数中所期望的行为。关键部分是这样的:

else {
return values.length;
}

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

于 2011-05-19T00:01:16.807 回答
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]});
    }
  }
}

然后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;
    } 
  })
}

(我没有测试这段代码,但你明白了。只要tag值相同,无论是reduce还是rereduce都没有关系tag。一旦不同的标签开始一起reduce,它就会检测到,因为值会改变。所以在那个时候开始积累。

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

同样在您的特定情况下,这是一个危险的 reduce 功能。您正在构建一个广泛的列表以查看所有具有标签的文档。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"}
]}
于 2011-05-19T05:25:26.807 回答