假设我有这样的用户集合: -
{
"_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
我考虑过的一些潜在方法: -
每种方法有什么可能,有什么好处/问题?
答案 0 :(得分:1)
你的第三种方法是要走的路:
弄清楚如何将事件和用户集合“加入”第三个集合我可以运行mapreduce
要执行此操作,您需要使用map-reduce所需的“已加入”数据创建新集合J
。您可以使用以下几种策略:
更新您的应用程序,以便在正常业务过程中插入/更新J
。在您需要非常频繁地运行MR并使用最新数据的情况下,这是最好的。它可以大大增加代码复杂性。从实现的角度来看,您可以直接(通过写入J
)或间接(通过将更改写入日志集合L
)然后将“新”更改应用于J
来执行此操作)。如果选择日志收集方法,则需要一种策略来确定更改的内容。有两个常见的:高水印(基于_id
或时间戳)并使用日志集合作为findAndModify
命令的队列。
以批处理模式创建/更新J
。对于高性能系统而言,这是一种方法,其中上述策略的多次更新会影响性能。如果您不需要经常运行MR和/或您不必保证最高的数据准确性,这也是可行的方法。
如果你选择(2)你将需要迭代你需要加入的集合中的文档 - 正如你已经想到的那样,Mongo map-reduce对你没有帮助。有很多种方法可以做到这一点:
如果您没有很多文档,如果它们很小,您可以通过直接连接到数据库来迭代数据库。
如果你不能做(1)你可以使用db.eval()
在数据库内部进行迭代。如果文档数量不小,请确保使用nolock: true
,因为db.eval
默认情况下是阻止的。这通常是我选择的策略,因为我倾向于处理非常大的文档集,而且我无法通过网络移动它们。
如果您不能执行(1)并且不想执行(2),则可以使用临时DB将集合克隆到另一个节点。 Mongo有一个方便的cloneCollection命令。请注意,如果数据库需要身份验证,这不起作用(不要问为什么;这是一个奇怪的10gen设计选择)。在这种情况下,您可以使用mongodump
和mongorestore
。一旦您将数据本地化为新数据库,您就可以根据需要参与其中。完成MR后,您可以更新生产数据库中的结果集合。我使用此策略进行一次性map-reduce操作,并进行大量预处理,以便不加载生产副本集。