В настоящее время у меня есть приложение, работающее в стандартной среде 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)
РЕДАКТИРОВАТЬ: я попробовал итеративную стратегию выборки страниц, описанную в ">ссылка из ответа ниже. Мой код был обновлен до следующего:
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()
, я не вижу улучшения.
РЕДАКТИРОВАТЬ:
Следуя приведенным ниже советам, я исправил проблему с помощью Projection Queries. Вместо того, чтобы иметь отдельную проекцию для каждого пользовательского запроса, я просто запускал одну и ту же проекцию каждый раз, а именно запрашивал все свойства объекта, за исключением строки JSON. Хотя это не идеально, поскольку каждый раз из базы данных по-прежнему извлекается ненужная информация, генерация отдельных запросов для каждого конкретного запроса не масштабируется из-за экспоненциального роста необходимых индексов. Для этого приложения, поскольку каждое дополнительное свойство является незначительной дополнительной памятью (кроме этой строки json), оно работает!