Mongodb PyMongo通过游标使用计算字段更新数组记录
对于非常大的数据集,精细聚合管道的收集输出基本上类似于以下内容:Mongodb PyMongo通过游标使用计算字段更新数组记录,mongodb,numpy,pymongo,Mongodb,Numpy,Pymongo,对于非常大的数据集,精细聚合管道的收集输出基本上类似于以下内容: { "_id" : { "clienta" : NumberLong(460011766), "clientb" : NumberLong(2886729962) }, "states" : [ [ "fixed", "fixed.rotated","fixed.rotated.off" ] ],
{
"_id" : {
"clienta" : NumberLong(460011766),
"clientb" : NumberLong(2886729962)
},
"states" : [
[
"fixed", "fixed.rotated","fixed.rotated.off"
]
],
"VBPP" : [
244,
182,
184,
11,
299,
],
"PPF" : 72.4,
}
在转换为数组之前,通过PyMongo直观地(尽管速度较慢)将这些字段更新为其以前的自我(数组的长度和方差)的计算,如下所示:
records_list = []
cursor = db.clientAgg.find({}, {'_id' : 0,
'states' : 1,
'VBPP' : 1,
'PPF': 1})
for record in cursor:
records_list.append(record)
for dicts in records_list:
dicts['states'] = len(dicts['states'])
dicts['VBPP'] = np.var(dicts['VBPP'])
我已经编写了各种形式的基本流程来优化速度,但是在将它们转换为数组以通过机器学习估计器之前,在内存中引入500k字典来修改它们是非常昂贵的。我尝试了各种方法,通过光标直接更新记录,但没有成功:
cursor = db.clientAgg.find().skip(0).limit(50000)
def iter():
for item in cursor:
yield item
l = []
for x in iter():
x['VBPP'] = np.var(x['VBPP'])
# Or
# db.clientAgg.update({'_id':x['_id']},{'$set':{'x.VBPS': somefunction as above }},upsert=False, multi=True)
我还尝试使用Mongo的常用运算符,但没有成功,因为方差非常简单,只需从数组的每个元素中减去平均值,将结果平方,然后对结果求平均值
如果我可以直接成功地修改集合,那么我就可以利用Monary或IOPro等非常快速的工具直接从Mongo将数据加载到numpy数组中,而不需要额外的开销
感谢您抽出时间MongoDB无法使用从文档字段计算的值更新文档;当前,您只能使用update将值设置为从应用程序传入的常量。因此,您可以将
document.x
设置为2,但不能将document.x
设置为document.y+document.z
或任何其他计算值
有关未来可能的功能,请参阅和
在不久的将来,PyMongo将发布一个新版本,允许您在一次网络往返中发送一批不同的更新操作,这将提高您的性能
附录:
我还有两个想法。首先,运行一些Javascript服务器端。例如,要将所有文档的b
字段设置为2*a
:
db.eval(function() {
var collection = db.test_collection;
collection.find().forEach(function(doc) {
var b = 2 * doc.a;
collection.update({_id: doc._id}, {$set: {b: b}});
});
});
第二个想法是使用,将集合转换为包含计算字段的第二个集合:
db.test_collection.aggregate({
$project: {
a: '$a',
b: {$multiply: [2, '$a']}
}
}, {
$out: 'test_collection2'
});
请注意,$project
必须明确包含所需的所有字段;默认情况下仅包括\u id
对于我机器上的一百万个文档,前一种方法需要2.5分钟,后一种方法需要9秒。因此,您可以使用聚合框架将数据从源复制到目标,并包含计算字段。然后,如果需要,将原始集合拖放到源名称
关于这一点,我的最后一个想法是,MongoDB 2.5.3及更高版本可以使用游标从聚合管道流式传输大型结果集。Monary没有理由不能使用该功能,所以您可以在那里提交功能请求。这将允许您通过Monary以您想要的形式从集合中获取文档,而无需实际将计算字段存储在MongoDB中。很有趣,谢谢您提供的信息。我搜遍了吉拉,但错过了那些伟大的发现。看来我必须把这些对象放到内存中,然后进行计算并写回常量。你对Python的可伸缩解决方案有什么建议吗。我无法控制一些$unwind操作符。遗憾的是,《Monary》的作者已经有相当一段时间处于MIA状态了。似乎没有办法从aggregate()倒带光标。find()只是cursor.rewind()。尝试使用聚合将得到“InvalidOperation:无法调用对命令游标的回放”True——为什么需要回放聚合游标?回放并不特殊;这与在循环中重新创建光标完全相同。倒带光标只需再次将查询发送到服务器,然后再次从服务器检索结果。(看。)所以你要么按照伯尼在谷歌群组中的建议去做(只获取一次结果并处理每个字段),要么创建一个新的光标来检索每个字段。