【问题标题】:'AVG' and 'SUM' functionality in MongoDB, any tips?MongoDB 中的“AVG”和“SUM”功能,有什么提示吗?
【发布时间】:2011-11-11 04:44:01
【问题描述】:

我是 MongoDB 的相对新手,但根据我所阅读的内容,有多种方法可以在 MongoDB 数据库中查找平均值和值的总和,每种方法都有不同的优点和缺点。

我主要是在寻求一种方法,以尽可能高效(快速)的方法找到一组值的总和,以及一组值的平均值。

正在查询的集合中的文档类似于这种结构(具有许多其他字段):

{
    "_id": ObjectId('4e650107580fd649e5000005'),
    "date_added": ISODate("2011-09-05T00:00:00Z"),
    "value": 1500
}

在我的应用程序中,预先计算诸如总和之类的东西并不总是可行的,因为要求和的值的选择可能会发生变化(基于日期范围 - 例如,在开始日期和结束日期之间,平均值是多少)。这是与预先计算平均值类似的问题。

根据我的阅读,MapReduce 绝对不适合实时(即按需)查找,因此这似乎也不可能。

目前我正在以这种方式查询集合:(注意:这是使用pymongo

response = request.db['somecollection'].find(
    {
        'date_added': {
            '$gte': date_start,
            '$lte': date_end
        }
    },
    {
        'value':1
    }
).limit(500)

然后在 Python 中使用 for 循环在响应上进行计算。 500 个结果的限制是任意的,以防止它变得太慢。我只检索值,而不检索其他字段。

这是进行此计算的最有效方法,还是有其他方法可以完成我的需要?

注意事项:

  • 我不能使用group 函数,因为我将来可能会使用分片
  • 我不能使用 MapReduce,因为它是用户即时使用的功能
  • 我无法预先计算很多总和/平均值,因为对总和/平均值的选择几乎总是不同的
  • 我查看了 stackoverflow 和网络,试图找到关于如何做这种事情的建议,而且它是相当开放的

编辑:

我应该指出,从我上面发布的查询返回的文档数量可能从 1 个文档到数百个不等,但可能返回的文档的最大数量约为 150 个(平均约为 60 或 70 个)

【问题讨论】:

    标签: mongodb nosql


    【解决方案1】:

    MongoDB 计划在 2.1.1 版(目前计划于 2011 年 11 月 1 日)中获得诸如 sum/avg/min/max 之类的本机聚合函数。有关更多详细信息和状态,请参阅问题:https://jira.mongodb.org/browse/SERVER-447

    【讨论】:

      【解决方案2】:

      MongoDB 笔记

      好的,所以 Map/Reduce 和聚合目前有一些严重的问题。

      大警告:MongoDB 实例只能有一个“javascript 引擎”实例。这意味着您不能在服务器上同时运行两个 Map/Reduce。而且你只有一个核心来运行 map-reduce。

      就您正在做的事情而言,您基本上是在“滚动自己的”M/R。缺点是额外的网络流量。好处是您现在可以在问题上投入更多的核心(来自网络服务器)。

      您的关键问题

      我无法预先计算很多总和/平均值,因为对总和/平均值的选择几乎总是不同的

      没有优化“所有可能的”查询的通用方法。如果您希望系统能够对每个范围的每个字段进行求和和聚合,那么您最终会发现一组太大的字段/范围。

      “解决”这个问题的方法是减少字段和范围的集合。

      所以保留每日/每小时计数器并对这些计数器求和。至少您减少了为回答您的查询而需要扫描的文档数量。

      【讨论】:

        【解决方案3】:

        简单的答案是:

        1. 如果可能的话,预先计算您可以预先计算的所有内容。
        2. 如果您需要按日期范围聚合数据并且聚合应该尽可能快地工作,那么使用 map/reduce + sharding 将计算分布到多台机器上。

        但同时mongodb指南说:

        使用 MapReduce 的代价是速度:组并不特别 速度快,但 MapReduce 速度较慢,不应该用于 “即时的。”您将 MapReduce 作为后台作业运行,它会创建一个 结果的集合,然后您可以实际查询该集合 时间。

        所以听起来 mongodb 并不是实时数据聚合的最佳解决方案。

        【讨论】:

        • 我肯定会预先计算所有我能做到的值。不幸的是,至少一开始我仅限于一台机器,所以我不能将它分布在多台机器上。在我的示例中,返回文档的数量是否足以影响考虑使用 MapReduce 的速度? (我在问题底部添加了返回的平均文档数)
        【解决方案4】:

        试试 map-reduce,它可能没有你想象的那么慢。我已经将它用于一些大型数据集的实时聚合,虽然它有时不是闪电般快,但它通常很好。最好能过滤掉要聚合的初始数据的大小,例如:

        db.collection.mapReduce(m, r, { query : { year: 2011 } });
        

        如果您需要进一步加快处理速度,请考虑将数据分布在分片集群上。然后可以在多个并行运行的分片上扩展 map-reduce 处理。

        【讨论】:

        • 我肯定会更多地尝试使用 MapReduce。我知道它会在数据集/查询/等之间有所不同,但在您的情况下,它是否足够快以至于用户不会真正注意到(即不到半秒)?
        • 在 500-5000 毫秒之间变化,但一些数据集非常大(100M+ 文档),因此需要一个繁忙/进度指示器,但速度足够快。当 JavaScript 引擎从单线程 SpiderMonkey 升级到 V8 时,Map-reduce 性能也应该会有所提高。
        • 啊,这听起来很有希望。目前我的数据集非常小(以数千为单位,而不是数百万),尽管这会随着时间的推移而增长。
        • 不要忘记您可以向 Map-Reduce 提供查询以限制输入。 MR 的可扩展性仍然不如直接查询(Javascript 限制要求一次只能运行一个 Map-Reduce 或其他 Javascript 任务),但是对于将结果过滤到您上面提到的大约 150 个的查询,它应该很漂亮快。
        • @Chris V8 不会提高 MongoDB 中 JavaScript 绑定功能的并发性或单线程特性。不过,它可能会提高性能。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-29
        • 2012-09-18
        • 2020-06-25
        • 2021-12-25
        • 2015-07-16
        • 2010-10-30
        • 2015-07-30
        相关资源
        最近更新 更多