基本上,非常大的数据集的复杂聚合管道的集合输出类似于以下内容:
{
"_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数组,而无需额外的开销。
感谢您的时间
答案 0 :(得分:3)
MongoDB无法使用从文档字段计算的值更新文档;目前,您只能使用update将值设置为从应用程序传入的常量。因此,您可以将document.x
设置为2,但不能将document.x
设置为document.y + document.z
或任何其他计算值。
有关未来可能的功能,请参阅https://jira.mongodb.org/browse/SERVER-11345和https://jira.mongodb.org/browse/SERVER-458。
在不久的将来,PyMongo将发布bulk API,允许您在单个网络往返中发送一批不同的更新操作,这将提高您的性能。
<强>附录:强>
我还有另外两个想法。首先,运行一些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}});
});
});
第二个想法是使用the aggregation framework's $out operator, new in MongoDB 2.5.2将集合转换为包含计算字段的第二个集合:
db.test_collection.aggregate({
$project: {
a: '$a',
b: {$multiply: [2, '$a']}
}
}, {
$out: 'test_collection2'
});
请注意,$project
必须明确包含您想要的所有字段;默认情况下仅包含_id
。
对于我机器上的一百万份文件,前一种方法需要2.5分钟,后一种方法需要9秒。因此,您可以使用聚合框架将数据从其源复制到目标,并包含计算字段。然后,如果需要,将原始集合和rename the target collection删除到源名称。
我最后的想法是,MongoDB 2.5.3及更高版本可以使用游标从聚合管道流式传输大型结果集。没有理由Monary无法使用该功能,因此您可以在那里提交功能请求。这样您就可以通过Monary以您想要的形式从集合中获取文档,而无需在MongoDB中实际存储计算字段。