使用pymongo在MongoDB集合中高效创建新字段

时间:2015-11-10 15:54:22

标签: mongodb pymongo

我有一个包含字段的文档的集合,称之为field1,我想在每个fxn条目上调用(复杂的)python函数field1并将其存储在一个新的field2。我的集合非常大,fxn需要几秒钟才能运行,所以我希望在一些工作中将其并行化。到目前为止,这是我的方法:

for i, entry in enumerate(collection.find().sort('_id')):
    if i % nJobs != jobID: continue
    field1 = entry['field1']
    field2 = fxn(field1)
    collection.update({'_id': entry['_id']}, {'$set': {'field2':field2})

其中nJobs是作业总数,jobID是当前作业的索引(例如,我说我并行运行此脚本5次,然后nJobs=5和{{1 }范围从0到4)

是否有更快或更可靠的方法来实现它?我希望将所有内容保存在python中,因为jobID需要保存在python中。

1 个答案:

答案 0 :(得分:1)

您基本上需要使用 Bulk API ,在for循环中,您可以利用写入命令Bulk API来执行批量更新操作,这些操作很简单服务器顶部的抽象,以便轻松构建批量操作。这些批量操作主要有两种形式:

  • 订购批量操作。这些操作按顺序执行所有操作,并在第一次写入错误时执行错误。
  • 无序批量操作。这些操作并行执行所有操作并聚合所有错误。无序批量操作不保证执行顺序。

这非常有效,因为您没有发送"每个"请求到服务器,但每1000个请求只有一次,api实际上为你排除了这个问题。请注意,对于比2.6更旧的服务器,API将下转换操作。但是,不可能将100%下转换,因此可能存在一些无法正确报告正确数字的边缘情况。

在非分片群集上实施此功能需要使用 snapshot 参数,以便您可以将查找光标与更新后的相同文档隔离开来:

bulk = db.collection.initialize_ordered_bulk_op()
counter = 0;

for entry in collection.find(snapshot = True):
    # process in bulk
    # calc field2 value first
    field2 = fxn(entry.field1)
    bulk.find({ '_id': entry._id }).update({ '$set': { 'field2': field2 } })
    counter++

    if ( counter % 1000 == 0 ):
        bulk.execute()
        bulk = db.collection.initialize_ordered_bulk_op()

if (counter % 1000 != 0):
    bulk.execute()