Update Umsetzung

Marcel Schwarz 2021-01-17 21:26:20 +00:00
parent f00c0c79d8
commit c80cdfdd17

@ -1,6 +1,8 @@
# Backend
## Datenbank
Die Entscheidung welche Datenbank benutzt werden sollte war relativ einfach, sie sollte vor allem leichtgewichtig sein, schnell und einfach zu bedienen. Aufgrund der hervorragenden Integration von SQLite in Python haben wir uns auch für SQLite entschieden. Sie bietet genug Datentypen, um alle unsere Anforderungen abzudecken.
Zunächst war es wichtig, zu erkennen, welche Tabellen nötig waren. Hier sind zunächst die Tabellen zu nennen, die die reine Datenhaltung der OpenApi Data abbilden.
#### usage_stats
```sql
@ -51,7 +53,53 @@ CREATE TABLE IF NOT EXISTS read_files(file_path TEXT, etag TEXT PRIMARY KEY)
Diese war notwendig um bei einem Abbruch der Initialisierung eine Wiederaufnahme des Prozesses zu ermöglichen. Es wird hierzu der Dateiname und der Dateihash (Checksumme) gespeichert.
## Datenaufbereitung (Praxis)
* Wie wurden die Parser geschrieben
#### Generelles Parserkonzept
Für jede der ca. 250 "usage-stats"-Dateien wird folgender Ablauf durchgeführt.
```mermaid
graph LR
DATA[Open Data] --> DOWNL[Herunterladen]
DOWNL --> PARSE[CSV parsen]
PARSE --> TRANS[Zeilen transformieren]
TRANS --> TYPING[Datentypen anpassen]
TYPING --> INSERT[in Datenbank schreiben]
```
Der Vorgang geschieht komplett im Arbeitsspeicher, was die maximale Lesegeschwindigkeit ermöglicht. Der Import dauert von 0 bis 100 % etwa 60 Minuten und verbraucht 6 Gigabyte Festplattenspeicher, sowie Netzwerktraffic.
Der wichtigste Teil, der Importer der "usage-stats", ist hier Ausschnittsweise abgebildet.
```python
mapped = []
for entry in entries:
try:
mapped.append((
# Rental Id
int(entry[0]),
# Duration oder Duration_Seconds
int(entry[1] or "-1"),
# Bike Id
int(entry[2] or "-1"),
# End Date
int(datetime.strptime(entry[3][:16], "%d/%m/%Y %H:%M").timestamp()) if entry[3] else -1,
# EndStation Id
int(entry[4] or "-1"),
# EndStation Name
entry[5].strip(),
# Start Date
int(datetime.strptime(entry[6][:16], "%d/%m/%Y %H:%M").timestamp()) if entry[6] else -1,
# StartStation Id
int(entry[7]),
# StartStation Name
entry[8].strip()
))
except ValueError as e:
LOG.error(f"Value Error {e} on line {entry}")
return
except KeyError as e:
LOG.error(f"Key Error {e} on line {entry}")
return
```
Obiges zeigt die Transformation, sowie die Datentypanpassung eines Eintrags. Es fällt sofort die konvertierung der Datumsangaben auf, sowie die "-1" Defaultwerte der Zahlenspalten. Ebenso kann ein Value Error auftreten, wenn das Datum nicht geparsed werden kann. Sollte dies passieren, wird der komplette Datensatz ignoriert. Gleiches gilt für eine Datei mit weniger Spalten wie erwartet (KeyError).
## Performance
* 60 Mio Datensätze