映射/减少 Couchbase 和 Couchbase 之间的差异云蚂蚁

发布于 2024-11-08 15:02:24 字数 933 浏览 4 评论 0原文

我一直在使用 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 忍者的见解...;)

I've been playing around with Couchbase Server and now just tried replicating my local db to Cloudant, but am getting conflicting results for my map/reduce function pair to build a set of unique tags with their associated projects...

// 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;
  }
}

In Cloudbase server this returns JSON like:

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

That's exactly what I wanted & expected. However, the same query on the Cloudant replica, returns this:

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

So it somehow only returns the length of the value array... Highly confusing & am grateful for any insights by some M&R ninjas... ;)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

心意如水 2024-11-15 15:02:24

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

else {
return values.length;
}

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

It looks like this is exactly the behavior you would expect given your reduce function. The key part is this:

else {
return values.length;
}

In Cloudant, rereduce is always called (since the reduce needs to span over multiple shards.) In this case, rereduce calls values.length, which will only return the length of the array.

倾城泪 2024-11-15 15:02:24

我更喜欢隐式减少/重新减少,而不是依赖于 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 值会发生变化,所以在那时我就开始积累

看来,它也很少值得。

这个技巧,尽管在我 strong>您的具体情况,这是一个危险的减少功能,如果您想查看所有文档,那么您正在构建一个宽列表来查看所有具有标签的文档。有标签,你可以映射它们

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

I prefer to reduce/re-reduce implicitly rather than depending on the rereduce parameter.

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

Then reduce checks whether it is accumulating document ids from the identical tag, or whether it is just counting different tags.

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

(I didn't test this code, but you get the idea. As long as the tag value is the same, it doesn't matter whether it's a reduce or rereduce. Once different tags start reducing together, it detects that because the tag value will change. So at that point just start accumulating.

I have used this trick before, although IMO it's rarely worth it.

Also in your specific case, this is a dangerous reduce function. You are building a wide list to see all the docs that have a tag. CouchDB likes tall lists, not fat lists. If you want to see all the docs that have a tag, you could map them.

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

Now you can query /db/_design/app/_view/docs_by_tag?key="3d" and you should get

{"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"}
]}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文