Python Google数据存储:ndb.put\u multi未返回

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库将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 == "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:])