2012-02-09 58 views
0

我有一个有趣的问题。我有一个可用的M/R版本,但它在小规模环境中并不是一个真正可行的解决方案,因为它太慢,查询需要实时执行。在没有MapReduce的情况下在MongoDB中应用函数和排序

我想遍历集合中的每个元素并对它进行评分,按降序排序,限制到前10位并将结果返回给应用程序。

这里是我想应用于伪代码中的每个文档的函数。

var score = 0; 
foreach(tag in document.Tags) { 
    score += someMap[tag]; 
} 
return score; 
+0

'someMap'的内容是否固定?或者他们会随着时间而改变,或者每个查询改变一次?如果它们在更新文档时是固定的并且已知的,那么最好的办法是做映射应用程序端并将分数直接插入到文档中(即插入到与'tags'平行的数组中,或者作为标量“分数”属性)。 – dcrosta 2012-02-09 14:42:28

+0

someMap由应用程序生成,因此它是已知的。我没有更新任何文件,我只是阅读他们的信息并给他们打分。 – Dharun 2012-02-09 14:55:22

+0

根据'someMap',写文档的应用程序可以插入他们的分数吗? – dcrosta 2012-02-09 15:03:07

回答

3

由于您的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} 
    ]}) 

这是一个有点复杂,和熊解释:

  1. 首先,我们以“放松”的标签阵列,从而使遵循管道处理文档中“标记”是标量的步骤 - 数组中标记的值 - 以及所有其他文档字段(特别是_id)针对每个展开的元素进行复制。
  2. 我们使用投影算子将标签转换为命名分数字段。每个大致的表达式(对于tag1score示例)“如果'tags'字段id中的文档中的值等于'a',则返回5并将该值分配给新字段tag1score,否则返回0并分配“。对于您的someMap中的每个标记/评分组合,都会重复此表达式。在此流水线中,每个文档将包含N tagNscore个字段,但其中至多有一个将具有非零值。
  3. 接下来我们使用另一个投影算子创建一个score字段,其​​值是文档中tagNscore字段的总和。
  4. 接下来,我们将这些文档按它们的_id进行分组,并将上一步中的score字段的值汇总到每个组中的所有文档中。
  5. 我们排序score,降(即最大得分第一)
  6. 我们仅限制于前10名的分数。

我会离开它作为一个练习读者如何someMap转换成正确的投影组在步骤2中,和正确的字段集在步骤3中添加

这主要是与应用程序代码或映射减少相同的一组步骤可以完成,但具有以下独特优势:不是map reduce,而是使用C++完全实现了聚合框架,并且它比map reduce更快并且更具并发性;与查询应用程序中的所有文档不同,聚合框架可与服务器端的数据配合使用,从而节省网络负载。但是,与其他两种方法一样,这仍然需要考虑每个文档,并且只能在计算所有分数后限制结果集。

+0

多么美妙的答案,谢谢。与此混淆了一段时间。我现在正在按照你的建议对应用程序进行所有计算,一旦出现2.2,我将按照你所说的完全遵循。 – Dharun 2012-02-09 17:25:50

+0

我应该提到 - 你可以从http://mongodb.org/downloads下载MongoDB 2.1或夜间开发版本。 2.1和睡衣都有聚合框架,但不推荐用于生产用途。 – dcrosta 2012-02-09 17:55:36

+0

文档确实提到了2.1中可用的聚合,我们将在开发中进行尝试。 – Dharun 2012-02-09 22:14:24

相关问题