【发布时间】:2018-02-23 02:50:05
【问题描述】:
我目前有一个在 Google App Engine 标准环境中运行的应用程序,其中包含一个大型天气数据数据库和一个生成该数据图表的前端端点。该数据库位于 Google Cloud Datastore 中,Python Flask 应用程序通过 NDB 库访问它。
我的问题如下:当我尝试为跨越大约一周的 WeatherData 生成图表时(数据每 5 分钟存储一次),我的应用程序超出了 GAE 的软私有内存限制并崩溃。但是,存储在我的每个 WeatherData 实体中的是我想要绘制图形的相关字段,此外还有一个非常大的 json 字符串,其中包含此图形应用程序不需要的预测数据。因此,导致我的应用程序超出软私有内存限制的部分 WeatherData 实体在此应用程序中甚至不需要。
因此,我的问题如下:是否有任何方法可以仅查询实体中的某些属性,例如可以针对 SQL 样式查询中的特定列进行查询?同样,我不需要整个预测 json 字符串来绘制图形,只需要存储在实体中的几个其他字段。我尝试运行的另一种方法是一次只获取几个实体并将查询拆分为多个 API 调用,但最终花费的时间太长以至于页面超时,我无法让它工作正确。
下面是我的代码,说明它目前是如何实现和破坏的。非常感谢任何输入:
wDataCsv = 'Time,' + ','.join(wData.keys())
qry = WeatherData.time_ordered_query(ndb.Key('Location', loc),start=start_date,end=end_date)
for acct in qry.fetch():
d = [acct.time.strftime(date_string)]
for attr in wData.keys():
d.append(str(acct.dict_access(attr)))
wData[attr].append([acct.time.strftime(date_string),acct.dict_access(attr)])
wDataCsv += '\\n' + ','.join(d)
# Children Entity - log of a weather at parent location
class WeatherData(ndb.Model):
# model for data to save
...
# Function for querying data below a given ancestor between two optional
# times
@classmethod
def time_ordered_query(cls, ancestor_key, start=None, end=None):
return cls.query(cls.time>=start, cls.time<=end,ancestor=ancestor_key).order(-cls.time)
编辑:我从下面的答案中尝试了link 中描述的迭代页面获取策略。我的代码已更新为以下内容:
wDataCsv = 'Time,' + ','.join(wData.keys())
qry = WeatherData.time_ordered_query(ndb.Key('Location', loc),start=start_date,end=end_date)
cursor = None
while True:
gc.collect()
fetched, next_cursor, more = qry.fetch_page(FETCHNUM, start_cursor=cursor)
if fetched:
for acct in fetched:
d = [acct.time.strftime(date_string)]
for attr in wData.keys():
d.append(str(acct.dict_access(attr)))
wData[attr].append([acct.time.strftime(date_string),acct.dict_access(attr)])
wDataCsv += '\\n' + ','.join(d)
if more and next_cursor:
cursor = next_cursor
else:
break
其中FETCHNUM=500。在这种情况下,我仍然超出了与以前相同长度的查询的软私有内存限制,并且查询需要更长的时间才能运行。我怀疑问题可能在于 Python 的垃圾收集器没有删除重新引用的已使用信息,但即使我包含 gc.collect() 我也看不到任何改进。
编辑:
按照以下建议,我使用投影查询解决了这个问题。我没有为每个自定义查询设置单独的投影,而是每次都运行相同的投影:即查询实体的所有属性,不包括 JSON 字符串。虽然这并不理想,因为它每次仍然从数据库中提取免费信息,但由于必要索引的指数增长,为每个特定查询生成单独的查询是不可扩展的。对于此应用程序,由于每个附加属性都是可忽略不计的额外内存(除了 json 字符串之外),它可以工作!
【问题讨论】:
标签: google-app-engine google-cloud-datastore app-engine-ndb