Когда я только начал разрабатывать этот проект, не было необходимости создавать большие файлы, но теперь это готовый продукт.
Короче говоря, 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')
Мы будем очень признательны за любые предложения.
Изменить:
Выше я задокументировал три возможных решения, основанных на моем исследовании, плюс предложения и т. Д.
Они не обязательно являются взаимоисключающими и могут быть небольшими вариациями или комбинациями любого из три, однако суть решений есть. Дайте мне знать, какой из них, по вашему мнению, наиболее разумен и может работать лучше всего.
Решение A: Используя mapreduce (или задачи), сериализуйте каждую запись и создайте запись memcache для каждой отдельной записи с ключом с именем ключа. Затем обработайте эти элементы по отдельности в файл pdf / xls. (используйте get_multi и set_multi)
Решение B: Используя задачи, сериализуйте группы записей и загрузите их в базу данных как большой двоичный объект. Затем после обработки всех записей запускайте задачу, которая загружает каждый большой двоичный объект, десериализует их, а затем загружает данные в окончательный файл.
Решение C: Используя mapreduce, получите имена ключей и сохраните их в виде списка или сериализованного большого двоичного объекта. Затем загрузите записи по ключу, что будет быстрее, чем текущий метод загрузки. Если бы я сделал это, что было бы лучше, сохранив их в виде списка (и каковы были бы ограничения ...Я предполагаю, что список из 100 000 будет вне возможностей хранилища данных) или в виде сериализованного большого двоичного объекта (или небольших фрагментов, которые я затем объединяю или обрабатываю)
Заранее благодарим за любой совет.