如何在另一个集合的键上映射reduce



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

{
  "_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/但我看不出这在这种情况下是如何应用的,因为它聚合了来自两个地方的值。。。我真正想做的就是执行查找。

在SQL中,我只需将扁平的UserGroup表加入事件表,然后只使用GROUP BY UserGroup.GroupName

我很乐意多次通过mapreduce。。。第一次通过UserId计数到类似{"_id":"1234","count":9}的内容,但我在下一次通过时遇到了问题…如何包括组id

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

  • 在事件文档中包含组信息(不可行)
  • 弄清楚如何"加入"用户集合或从map函数中查找用户组,这样我也可以发出组id(不知道如何做到这一点)
  • 弄清楚如何将事件和用户集合"连接"到第三个集合中,我可以在上面运行mapreduce

每种方法都有哪些可能,有哪些好处/问题?

您的第三种方法是:

找出如何将事件和用户集合"连接"到第三个集合中我可以在上运行mapreduce

要做到这一点,您需要创建一个新的集合J,其中包含地图缩减所需的"联接"数据。有几种策略可以用于此:

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

  2. 以批处理模式创建/更新J。在高性能系统的情况下,上述策略的多次更新会影响性能。如果您不需要非常频繁地运行MR和/或不必保证高达第二级的数据准确性,这也是一种方法。

如果使用(2),您将不得不迭代需要加入的集合中的文档——正如您所发现的,Mongo-map-reduce在这里对您没有帮助。有很多可能的方法可以做到这一点:

  1. 如果您没有太多的文档,并且它们很小,那么您可以通过与数据库的直接连接在数据库之外进行迭代。

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

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

祝你好运!

相关内容

  • 没有找到相关文章

最新更新