Als ich mit der Entwicklung dieses Projekts begann, war es nicht erforderlich, große Dateien zu erstellen, es ist jetzt jedoch ein Ergebnis.Wie generiere ich große Dateien (PDF und CSV) mit AppEngine und Datastore?
Lange Rede, kurzer Sinn, GAE spielt einfach nicht gut mit großen Datenmanipulationen oder der Generierung von Inhalten. Abgesehen von der Tatsache, dass keine Dateispeicher vorhanden sind, scheint selbst etwas so Einfaches wie das Erzeugen einer PDF mit ReportLab mit 1500 Datensätzen einen DeadlineExceededError zu treffen. Dies ist nur ein einfaches PDF, das aus einer Tabelle besteht.
Ich verwende den folgenden Code ein:
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)
Nichts besonders schick, aber es Drosseln. Gibt es einen besseren Weg, dies zu tun? Wenn ich in irgendeine Art von Dateisystem schreiben könnte und die Datei in Bits erzeugen könnte, und dann wieder beitreten, könnte das funktionieren, aber ich denke, das System schließt dies aus.
Ich muss das gleiche für eine CSV-Datei tun, aber die Grenze ist offensichtlich ein bisschen höher, da es nur Rohausgabe ist.
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')
Alle Vorschläge würden sehr geschätzt werden.
Edit:
Above ich drei mögliche Lösungen auf meiner Forschung basiert dokumentiert hatte, sowie Vorschläge etc
Sie sind nicht unbedingt gegenseitig aus, und konnte eine leichte Variation oder Kombination von irgendwelchen sein die drei, aber der Kern der Lösungen ist da. Lass mich wissen, welches deiner Meinung nach am meisten Sinn macht und vielleicht das Beste macht.
Lösung A: Verwenden Sie Mapreduce (oder Aufgaben), serialisieren Sie jeden Datensatz und erstellen Sie einen Memcache-Eintrag für jeden einzelnen Datensatz, der mit dem Schlüsselnamen codiert ist. Verarbeiten Sie diese Elemente dann einzeln in die pdf/xls-Datei. (Verwenden Sie get_multi und set_multi)
Lösung B: Verwenden Sie Aufgaben, serialisieren Gruppen von Datensätzen und laden Sie sie als Blob in die Datenbank. Dann lösen Sie eine Aufgabe aus, sobald alle Datensätze verarbeitet sind, die jeden Blob laden, deserialisieren und dann die Daten in die endgültige Datei laden.
Lösung C: Verwenden Sie mapreduce, rufen Sie die Schlüsselnamen ab und speichern Sie sie als Liste oder serialisierten Blob. Dann laden Sie die Datensätze per Schlüssel, was schneller wäre als die aktuelle Ladeart. Wenn ich dies tun würde, was wäre besser, sie als Liste zu speichern (und was wären die Einschränkungen ... ich nehme an, eine Liste von 100.000 würde die Fähigkeiten des Datenspeichers übersteigen) oder als serialisiertes Blob (oder klein Stücke, die ich dann verketten oder verarbeiten)
Vielen Dank im Voraus für eine Beratung.
Wahrscheinlich eine geringe Ineffizienz, aber data.append ([...]) wird viel effizienter sein als Daten + = [[...]]. –
Ich habe den Code bearbeitet, um dies widerzuspiegeln. Danke für den Tipp! – etc