Performance ist ein wichtiger Bestandteil bei der Arbeit mit Daten. Jede Aktion kostet Zeit und Ressourcen, wodurch es wichtig ist, die Arbeitsschritte zu überwachen, um möglichst Zeit und Ressourcen dabei einzusparen. Daher werden fortlaufend Updates für Datenbanken und ETL-Tools entwickelt, aber auch die Verarbeitung innerhalb dieser Datenbanken und Tools wird von den Entwicklern stets weiterentwickelt und optimiert. Doch woher weiß ich, dass ein Datenbank Update oder eine Anpassung an einem Statement zu einer Verbeserung geführt hat? Die einfachste Möglichkeit ist es bei einem ETL-Tool in den Log zu schauen und nach der Ausführungszeit zu suchen. Bei einer Datenbank kann man entsprechend in Systemtabellen oder Audit-Tabellen prüfen, wie lange diese Prozesse gedauert haben. Gerade bei Log Dateien kann dies ein aufwendiger Prozess sein. Außerdem ist ein einmaliger Abgleich der Ausführungszeiten noch keine Bestätigung für die Optimierung eines Prozesses. Das liegt daran, dass die Ausführungszeit eines Prozesses in den meisten Fällen nicht nur von dem eigenen Prozess abhängt, sondern auch von Prozessen, die parallel dazu in dem ETL-Tool oder auf der Datenbank ausgeführt werden. Daher ist es sinnvoll mehrere Ausführungszeiten zu betrachten, und dies am besten vor und nach der Anpassung. Wenn man selber schon einmal ein Logfile analysiert hat weiß man, wie lange es dauern kann, bis man die richtigen Informationen gefunden hat. Auch wenn man nach dem ersten Logfiles deutlich schneller mit der Struktur umgehen kann wird der Prozess mit der Menge an Logfiles nicht merklich schneller. Falls es sich bei den Anpassungen um ein Datenbank Update handelt ist es besser nicht nur einen Prozess, sondern mehrere Prozesse zu betrachten. So steigt die Zahl der auszuwertenden Logfiles von einzelnen Files schnell in Bereiche von mehreren hundert Files. Spätestens jetzt sollte einem klar werden, dass diese Arbeit nicht ohne Rechenleistung erledigt werden sollte. Dafür eignen sich Programme wie elasticsearch und Python.
Elasticsearch ist eine Suchmaschine, in der beispielsweise unsere Logfiles abgelegt werden können. Mit Hilfe der Rest API kann anschließend auf die einzelnen Logfiles gefiltert werden. Doch wie kann man das für eine Auswertung nutzen? Hier kommt Python ins Spiel. Python ist durch seine zahlreichen Bibliotheken ein passendes Tool für die Auswertung der Datein. Zusätzlich bietet Python eine entsprechende Anbindung an elasticsearch.
Um mit Python auf die Daten der Rest API zugreifen zu können, muss zunächst das elasticsearch package auf Python installiert werden.
Pip install elasticsearch
Anschließend können wir über Python mit der Auswertung beginnen. Zunächst importieren wir die elasticsearch library um darauf zugreifen zu können und definieren eine elasticsearch Datenbank
from elasticsearch
import Elasticsearch
es = Elasticsearch([{'host'_'localhost','port':9200}])
Im Internet gibt es eine Reihe von öffentlichen Rest APIs mit denen man die Möglichkeit hat, die Funktionsweise von Python und elasticsearch zu lernen. In unserem Beispiel nehmen wir eine Datenbank über die Rennergebnisse von allen Formel 1 Rennen zwischen 1950 und 2019. In einem ersten Schritt importieren wir diese Daten aus der Rest API in unsere elasticsearch Datenbank. Dabei legen wir einen Index an um diesen später zu durchsuchen
i = 1
while r.status_code == 200:
r = requests.get('http://ergast.com/api/f1/1950/' + str(i) + '/results')
es.index(index="f11950", doc_type="doc", id=i, body=json.loads(r.content))
i = i+1
print(i)
Hier wird für jeden Status der Anfrage ein Eintrag in dem Index „f11950“ angelegt. In diesem Beispiel werden alle Rennergebnisse des Jahres 1950 in den Index eingetragen. Damit alle Ergebnisse eingelesen werden können wird eine doppelte Schleife benötigt, um über die Jahre und die Rennen zu gehen.
i=2000
j=1
length=[]
time=[]
laps=[]
year_R=[]
Race_R=[]
for i in year:
for j in race:
result = requests.get('https://ergast.com/api/f1/'+ str(i) +'/'
+ str(j) +'/restults.json')
if result.status_code == 200 and result.json()['MRData']['RaceTable']
['Races'] != []:
url = result.json()['MRData']['RaceTable']['Races'][0]['Circuit']
['url']
circuit = requests.get(url)
circ = circuit.text
circl = circ[circ.find('Length'):-1]
circlength = circl[15:20]
length.append(circlength)
timelap = result.json()['MRData']['RaceTable']['Races'][0]['Results']
[0]['Time']['time']
time.append(timelap)
lap = result.json()['MRData']['RaceTable']['Races'][0]['Results']
[1]['laps']
laps.append(lap)
year_R.append(i)
Race_R.append(j)
j=j+1
i=i+1
Wir wollen in diesem Beispiel die Durchschnittsgeschwindigkeit der “Formel 1” Wagen im Laufe der Jahre betrachten. Dafür können wir aus dem Ergebnis eines Requests über eine Filterung die Gesamtzeit des ersten Fahrers ausgeben lassen:
results.json()['MRData']['RaceTable']['Races'][0]['Results'][0]['Time']['time']
Die Eckigen Klammern öffnen dabei immer einen weiteren Bereich der unterliegenden json Abfrage. Neben der Zeit interessiert noch die Länge der Strecke. Da in der Datenbank nicht die zurückgelegte Strecke der Piloten eingetragen ist müssen wir einen Umweg gehen. Für jede Rennstrecke ist die url zur Wikipedia-Seite der Strecke angegeben. Pro url können wir nun über einen Request den Text der entsprechenden url nach dem Schlagwort Length durchsuchen. Anschließend nehmen wir die 5 Zeichen nach dem ersten Length im Textkörper der Rennstrecke. Diese Länge wird als Rundenlänge identifiziert. Da im Laufe der Zeit die Rundenanzahl immer wieder angepasst wurde müssen wir uns die Rundenanzahl ebenfalls aus einer json Abfrage ausgeben lassen. Zuletzt geben wir noch das Jahr und die Renn-nummer aus. Jeder Wert wird in eine Liste eingetragen, die wir anschließend untersuchen können.
Bei einem Datenbankupdate interessiert uns die Leistung der Datenbank vor und nach dem Update. Um diese Punkte voneinander unterscheiden zu können teilen wir die ermittelten Listen in zwei Bereiche. In unserem Beispiel wollen wir uns die Auswirkung von Heck- und Frontflügeln in der Formel 1 anschauen. Diese Flügel wurden im Jahr 1968 eingeführt. Dieses Jahr nehmen wir daher als unseren Referenzwert.
Da unsere bezüglich der Länge der Strecke nicht vollständig gefüllt ist und dort teilweise keine richtigen Werte eingetragen sind müssen wir diese falschen Informationen aus den Listen entfernen. Hierfür suchen wir die Liste length nach leeren Einträgen ab. Falls ein leerer Eintrag in dieser Liste vorhanden ist wird der Eintrag ignoriert.
Anschließend wird jeweils auf das Jahr geprüft und alle Werte vor 1968 werden in eine Liste mit dem Prefix “old_” eingetragen, während alle neueren Einträge in eine Liste mit dem Prefix “new_” eingetragen werden. Außerdem muss die Zeit in eine Sinnvolle Einheit gebracht werden, in unserem Fall in Sekunden.
lenlength = len(length)
while k < lenlength:
if length[k] != '' and length [k] != 'h row':
vlength = length[k][0:length[k].find(' ')]
totallength = float(laps[k])*float(vlength)
tottime = time[k]
hour = float(tottime[0:tottime.find(':')])
resttime1= float(tottime[tottime.find(':')+1:])
minute = float(resttime1[0:resttime1.find(':')])
resttime2= float(resttime1[resttime1.find(':')+1:])
second = float(resttime2)
time_in_s = hour*360+minute*60+second
if year_R[k] < 1968.0:
old_time_u.append(time_in_s)
old_totlength.append(totallength)
old_year_race.append(float(year_R[k])+float(Race_R[k])/21)
else:
new_time_u.append(time_in_s)
new_totlength.append(totallength)
new_year_race.append(float(year_R[k])+float(Race_R[k])/21)
Wir haben jetzt also zwei mal drei Listen, mit den unterschiedlichen Angaben year_race, welche der Zeitstempel für unsere Untersuchung ist und totlength, bzw. time_u aus denen wir die Durchschnittsgeschwindigkeit errechnen können.
Mit diesen Listen kann man einen Plot erstellen, auf dem man die Durchschnittsgeschwindigkeit in Abhängigkeit vom Jahr ermitteln kann.
In unserem Beispiel haben wir noch den Mittelwert der jeweiligen Zeiträume bestimmt und in das Diagramm eingetragen. Das Diagramm wurde anschließend mit Hilfe der Python-Bibliothek matplotlib.pyplot erstellt.
Eine weitere Ansprechende Darstellung kann ein Histogramm sein. Dafür können die gleichen Werte der Auswertung verwendet werden.
Aus beiden Plots kann man ersehen, dass die Geschwindigkeit nach der Einführung von Flügeln in der Formel 1 angestiegen ist. Analog dazu könnte eine Auswertung von Log Files aussehen, um zu bestätigen, dass durch ein Datenbank Update die Laufzeiten der Jobs verkürzt wurden.