mongodb - mongodb中的成对交叉点

标签 mongodb mapreduce

我是 mongodb 的新手,我想知道是否可以得到一些建议。我有以下收藏

{ "_id" : "u1", "item" : [ "a", "b", "c" ] }
{ "_id" : "u2", "item" : [ "b", "d", "e" ] }
{ "_id" : "u3", "item" : [ "a", "c", "f" ] }
{ "_id" : "u4", "item" : [ "c" ] }

我想创建一个新集合,为每对用户计算项目的并集和交集,例如在最后,对于用户 1 和 2,4 结果将是

{ "_id" : "u12", "intersect_count":1,"union_count":6 }
{ "_id" : "u14", "intersect_count":1,"union_count":4}

由于效率低下,我不想对每一对进行成对操作。有什么技巧可以更有效地做到这一点吗?

最佳答案

我的解决方案是这样的:

map_func = function() {
  self = this;
  ids.forEach(function(id) {
    if (id === self._id) return;
    emit([id, self._id].sort().join('_'), self.item);
  });
};

reduce_func = function(key, vals) {
  return {
    intersect_count: intersect_func.apply(null, vals).length,
    union_count: union_func.apply(null, vals).length
  };
};

opts = {
  out: "redused_items",
  scope: {
    ids: db.items.distinct('_id'),
    union_func: union_func,
    intersect_func: intersect_func
  }
}

db.items.mapReduce( map_func, reduce_func, opts )

如果您的集合中有 N 个元素,则 map_func 将发出 N*(N-1) 个元素以供将来减少。然后 reduce_func 会将它们缩减为 N*(N-1)/2 个新元素。

我使用 scope 将全局变量 (ids) 和辅助方法 (union_func, intersect_func) 传递到map_funcreduce_func。否则 MapReduce 将因错误而失败,因为它在特殊环境中评估 map_funcreduce_func

调用MapReduce的结果:

> db.redused_items.find()
{ "_id" : "u1_u2", "value" : { "intersect_count" : 1, "union_count" : 6 } }
{ "_id" : "u1_u3", "value" : { "intersect_count" : 2, "union_count" : 6 } }
{ "_id" : "u1_u4", "value" : { "intersect_count" : 1, "union_count" : 4 } }
{ "_id" : "u2_u3", "value" : { "intersect_count" : 0, "union_count" : 6 } }
{ "_id" : "u2_u4", "value" : { "intersect_count" : 0, "union_count" : 4 } }
{ "_id" : "u3_u4", "value" : { "intersect_count" : 1, "union_count" : 4 } }

我在测试中使用了以下助手:

union_func = function(a1, a2) {
  return a1.concat(a2);
};

intersect_func = function(a1, a2) {
  return a1.filter(function(x) {
    return a2.indexOf(x) >= 0;
  });
};

另一种方法是使用 mongo 游标而不是全局 ids 对象:

map_func = function() {
  self = this;
  db.items.find({},['_id']).forEach(function(elem) {
    if (elem._id === self._id) return;
    emit([elem._id, self._id].sort().join('_'), self.item);
  });
};

opts = {
  out: "redused_items",
  scope: {
    union_func: union_func,
    intersect_func: intersect_func
  }
}

db.items.mapReduce( map_func, reduce_func, opts )

结果是一样的。

关于mongodb - mongodb中的成对交叉点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13922230/

相关文章:

azure - 如何将较大的文件上传到 azure hadoop 集群?

node.js - 使用 $group stage 和 $sum 运算符聚合

mongodb - 过滤器内的 $eq 不适用于数组字段 - Mongodb

python - 如何在 Python 中打印和计算 MongoDB 中 Json 内的值

java - Hadoop Map Reduce - 将 Iterable<Text> 值写入上下文时,reduce 中的嵌套循环忽略文本结果

hadoop - OOZIE 工作流 : HIVE table did not exists but directory created in HDFS

node.js - HEROKU 和 HAPIJS 错误 R10(启动超时)-> Web 进程在启动后 60 秒内无法绑定(bind)到 $PORT

javascript - 错误 : `useFindAndModify` is an invalid option

hadoop - 从 RecordReader/InputFormat 访问作业的配置

java - MapReduce:结果不完整