如何从另一个集合中映射关键字

时间:2012-08-19 07:49:57

标签: mongodb mapreduce

假设我有这样的用户集合: -

{
  "_id" : "1234",
  "Name" : "John",
  "OS" : "5.1",
  "Groups" : [{
      "_id" : "A",
      "Name" : "Group A"
    }, {
      "_id" : "C",
      "Name" : "Group C"
    }]
}

我有一系列这样的事件: -

{
  "_id" : "15342",
  "Event" : "VIEW",
  "UserId" : "1234"
}

我能够使用mapreduce来计算每个用户的事件数量,因为我可以发出“UserId”并计算出来,但我现在要做的就是按组计算事件。

如果我在我的事件文档中有一个“Groups”数组,那么这很容易,但我不这样做,这只是一个例子,实际的应用程序要复杂得多,我不想复制所有数据都包含在事件文档中。

我在http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/看到了一个示例,但我看不出这种情况在这种情况下是如何适用的,因为它聚合了两个地方的值......我真正想做的就是执行查找。 / p>

在SQL中,我只是将我的扁平UserGroup表加入到事件表中,而只是将GROUP BY UserGroup.GroupName加入

我会对mapreduce的多次传递感到满意...第一次通过UserId计算成{{_id':“1234”,“count”:9}之类的东西但是我在下一次传球时卡住了...如何包含组ID

我考虑过的一些潜在方法: -

  • 在事件文档中包含组信息(不可行)
  • 了解如何“加入”用户集合或从地图功能中查找用户组,以便我也可以发出组ID(不知道如何执行此操作)
  • 找出如何将事件和用户集合“加入”第三个集合我可以运行mapreduce

每种方法有什么可能,有什么好处/问题?

1 个答案:

答案 0 :(得分:1)

你的第三种方法是要走的路:

  

弄清楚如何将事件和用户集合“加入”第三个集合我可以运行mapreduce

要执行此操作,您需要使用map-reduce所需的“已加入”数据创建新集合J。您可以使用以下几种策略:

  1. 更新您的应用程序,以便在正常业务过程中插入/更新J。在您需要非常频繁地运行MR并使用最新数据的情况下,这是最好的。它可以大大增加代码复杂性。从实现的角度来看,您可以直接(通过写入J)或间接(通过将更改写入日志集合L)然后将“新”更改应用于J来执行此操作)。如果选择日志收集方法,则需要一种策略来确定更改的内容。有两个常见的:高水印(基于_id或时间戳)并使用日志集合作为findAndModify命令的队列。

  2. 以批处理模式创建/更新J。对于高性能系统而言,这是一种方法,其中上述策略的多次更新会影响性能。如果您不需要经常运行MR和/或您不必保证最高的数据准确性,这也是可行的方法。

  3. 如果你选择(2)你将需要迭代你需要加入的集合中的文档 - 正如你已经想到的那样,Mongo map-reduce对你没有帮助。有很多种方法可以做到这一点:

    1. 如果您没有很多文档,如果它们很小,您可以通过直接连接到数据库来迭代数据库。

    2. 如果你不能做(1)你可以使用db.eval()在数据库内部进行迭代。如果文档数量不小,请确保使用nolock: true,因为db.eval默认情况下是阻止的。这通常是我选择的策略,因为我倾向于处理非常大的文档集,而且我无法通过网络移动它们。

    3. 如果您不能执行(1)并且不想执行(2),则可以使用临时DB将集合克隆到另一个节点。 Mongo有一个方便的cloneCollection命令。请注意,如果数据库需要身份验证,这不起作用(不要问为什么;这是一个奇怪的10gen设计选择)。在这种情况下,您可以使用mongodumpmongorestore。一旦您将数据本地化为新数据库,您就可以根据需要参与其中。完成MR后,您可以更新生产数据库中的结果集合。我使用此策略进行一次性map-reduce操作,并进行大量预处理,以便不加载生产副本集。

    4. 祝你好运!