这是关于频繁更新的子字典结构的问题。 CPU和IO之间的权衡。
内存中有一个嵌套的dict数据结构。代码1:
domain={}
domain["www.xx.com"]={}
domain["www.xx.com"]["192.105.0.1"]={}
domain["www.xx.com"]["192.105.0.1"]["TTLS"]=Set([20,80,3000])
domain["www.xx.com"]["192.105.0.1"]["FIRST_SEEM"]=1379484935.460281
domain["www.xx.com"]["192.105.0.1"]["LAST_SEEN"]=1379484945.46077
domain["www.xx.com"]["192.105.0.2"]={}
domain["www.xx.com"]["192.105.0.2"]["TTLS"]=Set([70,90,2000])
domain["www.xx.com"]["192.105.0.2"]["FIRST_SEEM"]=13794674935.460281
domain["www.xx.com"]["192.105.0.2"]["LAST_SEEN"]=1379674945.46077
然后序列化Set部分。代码2:
domain["www.xx.com"]["192.105.0.1"]["TTLS"]=list(domain["www.xx.com"]["192.105.0.1"]["TTLS"])
domain["www.xx.com"]["192.105.0.2"]["TTLS"]=list(domain["www.xx.com"]["192.105.0.2"]["TTLS"])
然后将此结构转储到mongodb,如Code 3:
db.myCollection.insert({"_id":"www.xx.com", "IPS":json.dumps(domain["www.xx.com"])})
该项目经常更新。新的一天到来,程序在内存中生成一个关于“www.xx.com”的新dict项目,然后它将使用mongodb中的以前信息更新此项目。是的,相反的方式,更简单的mongo更新。这里,json加载返回一个字典,就像转储的那样(除了集合)。代码4
mongo_dict=json.loads(db.myCollection.find_one({"_id":"www.xx.com"}))
update_domain_with_mongo_dict(mongo_dict)
所以,在这一天结束时,程序只是将整个域[“www.xx.com”]内存转储到mongo。这样可以节省文档更新工作,简化IO,将脏工作留给python程序。 (我已经读过很多关于mongo糟糕的子文档更新能力的抱怨。)代码5
db.myCollection.update({"_id":"www.xx.com"},{"$set":{"IPS":json.dumps(domain["www.xx.com"])}})
然而,似乎许多更新毫无意义。即使没有udpate发生或只是稍作更新,程序也必须将dict项恢复为mongodb。关于这一点,IO太大了。这是问题,我需要单独更新子文档,有许多for循环和new-update检查。所以,json转储/加载,再见。
然后,精制的mongo对象和代码可能如下所示:代码6
{
"_id":"www.xx.com"
"IPS":[
{
"IP":"192.168.0.1"
"TTLS":[20, 80, 3000]
"FIRST_SEEN":1379484935.460281
"LAST_SEEN":1379484945.46077
}
{
"IP":"192.168.0.2"
"TTLS":[70, 90, 2000]
"FIRST_SEEN":13794674935.460281
"LAST_SEEN":1379674945.46077
}
]
}
db.update({"_id":"www.xx.com"}, 'IPS'.0.'FIRST_SEEN':1379674945.46077)
然而,这种更新需要索引'0',这由密钥:ip决定。在这个结构中,我放弃了json转储/加载,这意味着放弃了dict。要获得索引,for循环是不可避免的。这可能会节省IO,但CPU会哭。
所以,伙计们,你读得太多了,你的选择是什么?任何奇妙的解决方案,让我惊讶 如果我错过了什么,请告诉我。感谢。
答案 0 :(得分:0)
您不需要在应用中跟踪所有这些内容。 Mongo非常强大
添加您要使用的新内容时$push
db.myCollection.update(
{"_id":"www.xx.com"},
{"$push":{"IPS": <new to be added>}}
)
这意味着您可以单独添加每个项目,而不是一次性全部放入。但最重要的是,这可以让你成长,而无需关心那里的内容。如果必须,您还可以添加$ each来执行此操作。
如果要更新内容,而不是跟踪索引,请在数组中的值上找到元素:
db.myCollection.update(
{"_id":"www.xx.com", "IPS.IP" <IP Entry>},
{"$set":{"IPS.$.LAST_SEEN": <new date value>}}
)
因此,使用位置运算符将确保更新发生在匹配的“IP”的位置。
如果您真的担心延迟,那么也许您的用例可能允许您拨回write concern。您可以阅读该参考资料,以了解您可以通过哪些方法来快速编写响应速度。
无论如何,您应该能够稍微回退一下这些信息的应用程序存储,而不是尝试跟踪所有内容,只是实现这些方法。也就是说,如果你有一些变化,你甚至需要保留那部分。
所以一定要保留一个缓存,不要写每个更新。但是当你写作时,将其清除并使用这些操作,你就可以从你的写作中获得价值。
在你那里的时候花点时间看一下full operator reference。