【问题标题】:MongoDB Aggregation as slow as MapReduce?MongoDB 聚合和 MapReduce 一样慢?
【发布时间】:2012-12-12 17:59:47
【问题描述】:

我刚开始使用 mongo db 并尝试做一些简单的事情。我用包含“item”属性的数据集合填充了我的数据库。我想尝试计算每个项目在集合中的时间

文档示例:

{ "_id" : ObjectId("50dadc38bbd7591082d920f0"), "item" : "Pons", "lines" : 37 }

所以我设计了这两个函数来做 MapReduce(使用 pymongo 用 python 编写)

all_map = Code("function () {"
           "    emit(this.item, 1);"
           "}")

all_reduce = Code("function (key, values) {"
                  " var sum = 0;"
                  " values.forEach(function(value){"
                  "     sum += value;"
                  " });"
                  " return sum;"
                  "}")

这就像一个魅力,所以我开始填充收藏。在大约 30.000 个文档中,mapreduce 已经持续了超过一秒...因为 NoSQL 吹嘘速度,我想我一定是做错了某些事情

Stack Overflow 上的一个问题让我查看了 mongodb 的聚合功能。所以我尝试使用 group + sum + sort thingies。想出了这个:

db.wikipedia.aggregate(
 { $group: { _id: "$item", count: { $sum: 1  }  } }, 
 { $sort: {count: 1}  }
)

这段代码工作得很好,给我的结果与 mapreduce 集相同,但它同样慢。难道我做错了什么?我真的需要使用 hadoop 等其他工具来获得更好的性能吗?

【问题讨论】:

  • $group 无法使用索引,然后您正在对计算字段进行全表扫描和排序,该计算字段再次无法使用索引...嗯,是的,我认为这很容易变得很慢和 MR ,请查看 $sort 上的注意事项:docs.mongodb.org/manual/reference/aggregation/#_S_sort。老实说,我不认为这是工具的错,而是更多的模式设计,如果你需要在实时的时间内进行这样的查询
  • 阅读此内容以获得澄清:stackoverflow.com/questions/12015064/…
  • @Sammaye 当您阅读我的结束语时,您会注意到我并没有对这些工具大发雷霆。我还没有使用 NoSQL 和 MongoDB 的经验。我只是问有什么问题。我如何改进我的设计以使这件事以正确的方式运行。
  • 我并没有责备你的愤怒:) 我是在说明我认为问题出在哪里。嗯,一个额外的预聚合集合是一个很好的起点,所以每次添加 item 时,您都会将该行(可能在您的应用程序中)ping 到另一个集合,它将使用 $inc 运算符更新此数据。这可能是最好的方法,无需过多阅读。当然,这确实意味着您要管理两个集合,但管理它们会比您进行查询更快、更容易。
  • @Sammaye 好吧,老实说,我发现您的反馈非常有建设性,所以我只是想确定一下;)我也在考虑为此提供两个集合解决方案。它在 NoSQL 故事中更有意义,然后尝试创建更复杂的查询。非常感谢您指出对计算字段进行排序确实有点慢:)

标签: mongodb mapreduce pymongo nosql


【解决方案1】:

我将给出一个基本上总结我的 cmets 的答案。我不能代表 Hadoop 等其他技术,因为我还没有找到时间使用它们的乐趣,但我可以代表 MongoDB。

不幸的是,您对任何数据库都使用了两个最差的运算符:计算字段和全表扫描上的分组(或不同)。在这种情况下,聚合框架必须计算字段、组,然后在内存中 (http://docs.mongodb.org/manual/reference/aggregation/#_S_sort) 对计算字段进行排序。对于 MongoDB 来说,这是一项效率极低的任务,实际上很可能是任何数据库。

没有简单的方法可以根据您自己的应用程序实时执行此操作。如果您不需要立即返回结果,则 Map reduce 可能是一种出路,但由于我猜您真的不想等待这种东西,因此默认方法只是完全消除该组。

您可以通过预聚合来做到这一点。因此,您可以创建另一个grouped_wikipedia 集合,并在您的应用程序中使用upsert()$set$inc 等原子运算符来管理它(以计算出现次数),以确保每个@987654326 只获得一行@。这可能是解决这个问题的最明智的方法。

然而,这确实引发了另一个问题,即必须在细节集合wikipedia 旁边管理这个额外的集合,但我相信这是在此处获得正确性能的不可避免的副作用。收益将大于必须管理额外收藏的损失。

【讨论】:

  • 但是,如果您有一个包含 800 万个条目的集合,并且您不断地在其上运行 map 和 reduce 以使您的“缓存”保持最新,这不会减慢您的数据库吗?跨度>
  • @RobertReiz 有可能,它取决于很多因素。我的意思是你确实有一个 JS 引擎的重量,但是 JS enigne 不再是单线程的,它可以在处理时释放数据库上的锁,所以问题是一旦 MR 写入数据库所需的 IO已经完成了,但是,如果你运行一个 MR,它只选择说,每 5 分钟 10,000 行,你会发现 MongoDB 可以很高兴地处理这个
  • 我不太关心客户端,而是mongodb进程。假设我有 800 万个条目,每个条目 MongoDB MR 需要 5 分钟,那么我需要 27 天来计算我所有的缓存。这与实时相差甚远:-)
  • @RobertReiz 是 mongod 进程,mongod 进程将启动其内置的 JS enigne, v8 in 2.2+。您集合中的每个条目都需要 mongodb 5 分钟来计算?等等,如何,为什么?
  • @RobertReiz 请记住,如果您每 5 分钟再次运行所有 8m 条记录,这并不是一项增量 MR 工作
猜你喜欢
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 2020-10-05
  • 2020-08-20
  • 1970-01-01
相关资源
最近更新 更多