Когда я впервые начал разработку этого проекта, не было необходимости создавать большие файлы, однако теперь он является готовым.
Короче говоря, GAE просто не очень хорошо справляется с крупномасштабными манипуляциями с данными или генерацией контента. Помимо отсутствия файлового хранилища, даже такого простого, как создание PDF-файла с ReportLab с 1500 записями, похоже, возникла ошибка DeadlineExceededError. Это простой PDF-файл из таблицы.
Я использую следующий код:
self.response.headers['Content-Type'] = 'application/pdf'
self.response.headers['Content-Disposition'] = 'attachment; filename=output.pdf'
doc = SimpleDocTemplate(self.response.out, pagesize=landscape(letter))
elements = []
dataset = Voter.all().order('addr_str')
data = [['#', 'STREET', 'UNIT', 'PROFILE', 'PHONE', 'NAME', 'REPLY', 'YS', 'VOL', 'NOTES', 'MAIN ISSUE']]
i = 0
r = 1
s = 100
while ( i < 1500 ):
voters = dataset.fetch(s, offset=i)
for voter in voters:
data.append([voter.addr_num, voter.addr_str, voter.addr_unit_num, '', voter.phone, voter.firstname+' '+voter.middlename+' '+voter.lastname ])
r = r + 1
i = i + s
t=Table(data, '', r*[0.4*inch], repeatRows=1 )
t.setStyle(TableStyle([('ALIGN',(0,0),(-1,-1),'CENTER'),
('INNERGRID', (0,0), (-1,-1), 0.15, colors.black),
('BOX', (0,0), (-1,-1), .15, colors.black),
('FONTSIZE', (0,0), (-1,-1), 8)
]))
elements.append(t)
doc.build(elements)
Ничего особенного, но это душит. Есть лучший способ сделать это? Если бы я мог записать в какую-то файловую систему и сгенерировать файл в битах, а затем присоединиться к ним, это могло бы сработать, но я думаю, что система исключает это.
Мне нужно сделать то же самое для файла CSV, однако ограничение, очевидно, немного выше, поскольку это просто необработанный вывод.
self.response.headers['Content-Type'] = 'application/csv'
self.response.headers['Content-Disposition'] = 'attachment; filename=output.csv'
dataset = Voter.all().order('addr_str')
writer = csv.writer(self.response.out,dialect='excel')
writer.writerow(['#', 'STREET', 'UNIT', 'PROFILE', 'PHONE', 'NAME', 'REPLY', 'YS', 'VOL', 'NOTES', 'MAIN ISSUE'])
i = 0
s = 100
while ( i < 2000 ):
last_cursor = memcache.get('db_cursor')
if last_cursor:
dataset.with_cursor(last_cursor)
voters = dataset.fetch(s)
for voter in voters:
writer.writerow([voter.addr_num, voter.addr_str, voter.addr_unit_num, '', voter.phone, voter.firstname+' '+voter.middlename+' '+voter.lastname])
memcache.set('db_cursor', dataset.cursor())
i = i + s
memcache.delete('db_cursor')
Буду очень признателен за любые предложения.
Edit:
Выше я задокументировал три возможных решения, основанных на моих исследованиях, плюс предложения и т. Д.
Они не обязательно являются взаимоисключающими и могут быть небольшим изменением или комбинацией любого из трех, однако суть решений есть. Дайте мне знать, какой из них, по вашему мнению, имеет наибольшее значение и может работать лучше.
Решение A: Используя mapreduce (или задачи), сериализуйте каждую запись и создайте запись memcache для каждой отдельной записи, для которой введено имя ключа. Затем обработайте эти элементы по отдельности в файл pdf / xls. (используйте get_multi и set_multi)
Решение B: Используя задачи, сериализуйте группы записей и загружайте их в БД в виде большого двоичного объекта. Затем запустите задачу после обработки всех записей, которые будут загружать каждый BLOB-объект, десериализовать их и затем загрузить данные в окончательный файл.
Решение C: Используя mapreduce, получите имена ключей и сохраните их в виде списка или сериализованного большого двоичного объекта. Затем загрузите записи по ключу, который будет быстрее, чем текущий метод загрузки. Если бы я сделал это, что было бы лучше, хранить их в виде списка (и каковы будут ограничения ... Я предполагаю, что список из 100 000 будет выше возможностей хранилища данных) или как сериализованный большой двоичный объект (или маленький куски, которые я потом соединяю или обрабатываю)
Заранее спасибо за любой совет.