情况如下:我有一个MongoDB集群和一个web应用程序,它可以执行相当密集的Map/Reduce查询。该查询在cron作业中周期性地(每5分钟(发生一次,结果存储(使用$merge
(到集合中。
工作原理:当前,查询对其集合中的每个记录执行。所说的集合正在慢慢增长到数百万行,每次运行都需要更长的时间。
显而易见的解决方案是对新记录运行Map/Reduce,并对旧存储的值使用Reduce函数来计算正确的值。MongoDB非常棒,它允许您指定一个reduce
选项,而不是merge
。
我不知道的是:如何仅对初始集合中的新记录正确执行M/R。我看到了两种潜在的解决方案,但都不好。想法?
- 我可以标记已处理的记录。问题是如何标记与我刚刚M/R覆盖的记录完全相同的记录
- 我可以查询匹配的项目,然后将ID列表作为
$in: [id1, id2, ...]
查询传递给Map/Reduce,然后发送更新以使用相同的$in
设置我的标志。但这真的很不雅,我不知道当唱片数量巨大时会如何表现
tl;dr:如何在将结果缩减为集合的Map/Reduce查询中只选择新记录。
#mongodb
IRC频道上的一个善良的灵魂帮助我解决了这个问题。一个简单的解决方案是有一个状态机字段,并执行以下操作(在伪代码中(:
set {state:'processing'} where {state:{$exists:false}}
mapreduce {...} where {state:'processing'}
set {state:'done'} where {state:'processing'}
现在,这是次优的,因为它在包含数百万条记录的集合上浪费了大量磁盘空间。但真正的问题是,为什么我没有早点想到这一点?