【问题标题】:Python with MongoDB documents iteration is very slow vs all documents as local variable in local RAM与所有文档作为本地 RAM 中的局部变量相比,带有 MongoDB 文档的 Python 迭代非常慢
【发布时间】:2021-12-23 07:53:29
【问题描述】:

我编写了一个脚本,将信息从一个集合中的大量文档转换为具有一些新键和值的另一个集合。

在 mongodb 中,我有 250k 个文档。 每个文档结构都是这样的:

{_id:1, city:'City 1', population:200, happinessRating:20, otherRating:5, ...}

{_id:2, city:'City X', population:3000, happinessRating:15, otherRating:7, ...}

我创建了一个 python 函数,它使用我在另一个集合中插入的新键和值在另一个文档中使用一些复杂的数学公式转换每个文档。

脚本的目的:

获得人口超过 500 人的独特(独特)城市,我有 共1300个城市。

循环抛出每个城市,获取所有文件 将特定城市作为城市键的值(例如:所有文档 具有“城市:'City 1'”)并为每个应用python函数 文档,然后将新转换的文档插入另一个 收藏。

场景 1:

我将一个查询中的所有文档从 mongodb 获取到一个局部变量 (所以我所有的东西都在 RAM 内存中)

我写了一些python代码来制作 一个字典,其中每个唯一城市的名称作为键,他的 文档作为列表 []。

我循环字典,应用函数, 将文档插入到新集合中。

最终新收集文档:250k 文档

执行时间:4 分钟

优点:非常快的执行时间

缺点:它需要超过 20GB 的 RAM,并且当文档数量为 1M 文档而不是 250k 文档时,它是不可扩展的

场景 2:

我做了一个 mongodb 聚合(或使用 distinct 函数),所以我得到了一个 人口超过 500 人的所有独特城市名称的列表。

所以现在我有一个包含 1300 个城市的列表。与场景 1 相同。

现在我做了一个循环,对于每个城市,我都会得到那个特定的 mongodb 文档 city,应用该函数,然后将文档插入到新集合中。

最终新收集文档:250k 文档

执行时间:72 分钟

优点:不需要太多RAM,小于500MB

缺点:需要很长时间才能完成执行

问题

所以我不明白为什么会这样。

在场景 1 中,我只对 mongodb 进行了 1 次查询,所以我的 RAM 内存中的 python 变量中的所有内容。

在场景 2 中,我对 mongodb 进行了 1301 次查询,1 次获取不同的唯一城市列表,每个城市 1 次查询

MongoDB 是本地服务器,所以连接速度非常快。在场景 1 中,将所有文档获取到 python 中的局部变量所需的时间不到 20 秒。

另一个重要信息是转换每个文档的函数非常复杂,我不能使用 MongoDB Aggregation 来转换它,所以我需要抛出那个 python 函数。

我希望我已经很好地解释了自己。

欢迎任何有关如何推进该项目的建议或意见。谢谢

【问题讨论】:

  • “非常复杂”是什么意思?你能提供吗?也许你可以做一个混合。或者考虑Bulk Write Operation
  • 聚合查询允许执行不同的操作,还允许循环通过不同的文档并对其应用一些逻辑,并将结果写入另一个集合。所有这一切都作为数据库服务器上的单个操作。这可能会带来更好的性能。
  • @WernfriedDomscheit 脚本超过 1k 行代码,我简化了示例来解释问题。为每个文档执行脚本后,有 300 个新字段。令我惊讶的是,对mongodb进行1301次查询需要1个多小时。它不应该几乎和场景 1 一样快吗?我们还在研究处理大量数据和创建新索引的世界,我们仍在开发和测试中,自从我在不到一周前开始使用 mongodb 以来,我在 python 方面做得更好。
  • @WernfriedDomscheit 例如,其中一个字段是通过按日期对一组城市进行排序来计算的,如果满足某些条件,则创建一个计数器,然后逆序更改日期,其他索引是再次计数,然后进行数学运算以创建百分比。
  • 我会更好地研究聚合查询,批量写入操作也许可以改进一些东西,但是 python 脚本已经花费了我 1 个多月的时间来熟悉 python 编程。聚合查询不能解决100%的字段,如果我只需要在python中计算一个字段,我需要再次对mongodb进行大量查询。我想了解如果我对 mongodb 进行大量查询,为什么要花这么长时间,如果我只做一个,我会在 ram 中创建所有内容,然后将所有内容重新插入 mongo。跨度>

标签: python mongodb mongodb-query pymongo


【解决方案1】:

这并没有提供真正的答案,但它说明了组成动态聚合管道、重用运算符并使其清晰排列的原理:

var match = {}
match["$match"] = { a: 1 }

var sort = { b: -1 }

var pipeline = [];
pipeline.push(match);
pipeline.push({ $sort: sort });
pipeline = pipeline.concat({ $skip: 5 }, { $limit: 3 })

db.collection.aggregate(pipeline, { allowDiskUse: true })

你可以试试看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-15
    • 2015-07-18
    • 2014-09-26
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 2020-04-27
    相关资源
    最近更新 更多