在没有MapReduce的情况下在MongoDB中应用函数和排序
我有一个有趣的问题。我有一个可用的M/R版本,但它在小规模环境中并不是一个真正可行的解决方案,因为它太慢,查询需要实时执行。在没有MapReduce的情况下在MongoDB中应用函数和排序
我想遍历集合中的每个元素并对它进行评分,按降序排序,限制到前10位并将结果返回给应用程序。
这里是我想应用于伪代码中的每个文档的函数。
var score = 0;
foreach(tag in document.Tags) {
score += someMap[tag];
}
return score;
由于您的someMap
正在改变每一次,我没有看到任何其他的替代比得分的所有文件,并返回得分最高的。无论您采用哪种方法进行此类操作,您都必须考虑集合中的所有文档,这些文档的速度会很慢,并且随着您扫描的集合的增长,它将变得越来越昂贵。
map reduce的一个问题是,每个mongod
实例只能运行一个并发map reduce。这是javascript引擎的一个限制,它是单线程的。缩小的多个地图将被交织,但它们不能彼此同时运行。这意味着,如果您依赖地图缩减来实现“实时”使用,也就是说,如果您的网页必须运行地图缩减渲染,那么您最终会达到页面加载时间变得无法接受的缓慢限制。
您可以通过查询所有文档到应用程序中,并在应用程序代码中进行评分,排序和限制来解决此问题。与map reduce不同,MongoDB中的查询可以同时运行,但这当然意味着您的应用程序服务器将不得不做很多工作。
最后,如果您愿意等待MongoDB 2.2发布(应该在几个月内),您可以使用新的aggregation framework代替映射缩减。您将不得不按摩someMap
以生成正确的管道步骤。下面是什么,这可能看起来像如果someMap
是{"a": 5, "b": 2}
一个例子:
db.runCommand({aggregate: "foo",
pipeline: [
{$unwind: "$tags"},
{$project: {
tag1score: {$cond: [{$eq: ["$tags", "a"]}, 5, 0]},
tag2score: {$cond: [{$eq: ["$tags", "b"]}, 3, 0]}}
},
{$project: {score: {$add: ["$tag1score", "$tag2score"]}}},
{$group: {_id: "$_id", score: {$sum: "$score"}}},
{$sort: {score: -1}},
{$limit: 10}
]})
这是一个有点复杂,和熊解释:
- 首先,我们以“放松”的标签阵列,从而使遵循管道处理文档中“标记”是标量的步骤 - 数组中标记的值 - 以及所有其他文档字段(特别是
_id
)针对每个展开的元素进行复制。 - 我们使用投影算子将标签转换为命名分数字段。每个大致的表达式(对于
tag1score
示例)“如果'tags'字段id中的文档中的值等于'a',则返回5并将该值分配给新字段tag1score
,否则返回0并分配“。对于您的someMap
中的每个标记/评分组合,都会重复此表达式。在此流水线中,每个文档将包含NtagNscore
个字段,但其中至多有一个将具有非零值。 - 接下来我们使用另一个投影算子创建一个
score
字段,其值是文档中tagNscore
字段的总和。 - 接下来,我们将这些文档按它们的
_id
进行分组,并将上一步中的score
字段的值汇总到每个组中的所有文档中。 - 我们排序
score
,降(即最大得分第一) - 我们仅限制于前10名的分数。
我会离开它作为一个练习读者如何someMap
转换成正确的投影组在步骤2中,和正确的字段集在步骤3中添加
这主要是与应用程序代码或映射减少相同的一组步骤可以完成,但具有以下独特优势:不是map reduce,而是使用C++完全实现了聚合框架,并且它比map reduce更快并且更具并发性;与查询应用程序中的所有文档不同,聚合框架可与服务器端的数据配合使用,从而节省网络负载。但是,与其他两种方法一样,这仍然需要考虑每个文档,并且只能在计算所有分数后限制结果集。
'someMap'的内容是否固定?或者他们会随着时间而改变,或者每个查询改变一次?如果它们在更新文档时是固定的并且已知的,那么最好的办法是做映射应用程序端并将分数直接插入到文档中(即插入到与'tags'平行的数组中,或者作为标量“分数”属性)。 – dcrosta 2012-02-09 14:42:28
someMap由应用程序生成,因此它是已知的。我没有更新任何文件,我只是阅读他们的信息并给他们打分。 – Dharun 2012-02-09 14:55:22
根据'someMap',写文档的应用程序可以插入他们的分数吗? – dcrosta 2012-02-09 15:03:07