Python Google数据存储:ndb.put\u multi未返回
我目前正在使用NDB库将XML文件中的一些实体重新插入到Google数据存储中。我观察到的问题是,有时Python Google数据存储:ndb.put\u multi未返回,python,google-app-engine,google-cloud-datastore,app-engine-ndb,Python,Google App Engine,Google Cloud Datastore,App Engine Ndb,我目前正在使用NDB库将XML文件中的一些实体重新插入到Google数据存储中。我观察到的问题是,有时ndb.put\u multi()似乎不会返回,脚本会挂起等待返回 代码基本上执行以下操作: @ndb.toplevel def insertAll(entities): ndb.put_multi(entities) entities = [] for event, case in tree: removeNamespace(case) if (case.tag ==
ndb.put\u multi()
似乎不会返回,脚本会挂起等待返回
代码基本上执行以下操作:
@ndb.toplevel
def insertAll(entities):
ndb.put_multi(entities)
entities = []
for event, case in tree:
removeNamespace(case)
if (case.tag == "MARKGR" and event == "end"):
# get ndb.Model entities
tm, app, rep = decodeTrademark(case)
entities.append(tm)
for app_et in app:
entities.append(app_et)
for rep_et in rep:
entities.append(rep_et)
if (len(entities) > 200):
n_entitites += len(entities)
insertAll(entities)
entities = []
if(len(entities) > 0):
insertAll(entities)
我以前注意到过这种行为,但它似乎非常不确定,我想知道是否有方法可以正确调试它和/或在ndb.put\u multi
上设置超时,以便在给定时间后它没有返回时至少可以重试
提前感谢,原始答案(编辑前)
你的逻辑有缺陷insertAll()
可能永远不会被调用。app
和rep
在哪里定义?如果它们是在这个函数之外定义的,为什么它们在嵌套循环中?rep
中的任何实体都将被写入len(app)*len(tree)
次
另外,如果len(实体)
<200,情况如何?它位于3个嵌套循环内。当然,在某些情况下,迭代具有len(实体)
<200。如果在所有循环之后,总数为750,请考虑孤立实体。您将孤立150个实体
至少在循环运行后附加此项,以写入孤立实体(<200):
还可以尝试将200减少到较小的值,如100。根据实体的大小,200可能太多,无法在超时之前完成
您是否检查过是否写入了任何实体
另外,您确定您了解数据存储所使用的实体是什么吗?如果只是从XML文件中提取字符串,则这些字符串不是实体rep
和app
必须是数据存储实体的列表,tm
必须是实际的数据存储实体
更新:
好的,这更有意义,但是您仍然孤立了一些实体,并且无法控制put\u multi()
的大小。如果(len(entities)>200):
,您应该批处理它们:
# primitive way to batch in groups of 100
batch_size = 100
num_full_batches = len(entities) // batch_size
remaining_count = len(entities) % batch_size
for i in range(num_full_batches):
ndb.put_multi(entities[i * batch_size : (i+1) * batch_size])
if remaining_count > 0:
ndb.put_multi(entities[(i+1) * batch_size:])
如果实体太多,您应该将其发送到
任务队列
,从您之前留下的注释可以看出,此应用程序似乎达到了实体读/写限制,即1 op/s。您可以阅读有关数据存储限制的更多信息
作为替代方案,您可以尝试使用Cloud Firestore,因为它在数据存储模式下使用。基于Ikai Lan
单调递增的值是存储/读取/写入/严格顺序的值,如日志中的时间戳。在当前的数据存储实现中,它们将按顺序存储/读/写在同一位置/位置,并且数据存储将无法正确分割工作负载。因此,当OPS足够高且数据存储无法水平增长时,您会注意到速度减慢。这称为
在该数据存储之上,除此之外,例如,这意味着您可以在某个点上拥有各种热点
变通办法
官方文档中提到的解决方法之一是在索引值前添加哈希:
如果您确实有一个将单调递增的键或索引属性,那么您可以预先设置一个随机散列,以确保将键分片到多个平板电脑上
请阅读更多信息。
ndb.put_multi()
为我挂起如果我让它一次保存太多实体,请尝试减小批大小Anks@Alex我观察到了相同的行为,将批减少到100个实体会提高插入速度,但我还没有看到任何挂起NDB
肯定会引发异常或其他问题,而不是永远等待Hey@Alex,看来你的评论就是答案。你为什么不把它作为答案发布?@A.Queue我仍然注意到ndb上的一些挂起。put_multi甚至将实体数量减少到50个。我在问题追踪器上填写了一份错误报告,正在等待有人回来。你可能会这样做吗?哦,对不起,我在Stackoverflow和格式化上粘贴代码时出错了,将更新问题。我认为孤立实体不是问题,因为在退出以插入剩余的实体
之前存在if。但是,减少批量大小似乎确实对减少挂起和插入所需时间有很大的影响。遗憾的是,Taskqueues不是我的选项,因为文件有一个外部循环,写入需要是连续的。1 op/s仅适用于同一实体组中的实体,而事实并非如此。
# primitive way to batch in groups of 100
batch_size = 100
num_full_batches = len(entities) // batch_size
remaining_count = len(entities) % batch_size
for i in range(num_full_batches):
ndb.put_multi(entities[i * batch_size : (i+1) * batch_size])
if remaining_count > 0:
ndb.put_multi(entities[(i+1) * batch_size:])