- Good evening ladies and gentlemen, this is your Flugzeugführer speakin'. We welcome you aboard of Cash & Flight Airways on our flight through the night. Ich gebe nur das Motto aus: "Wind um die Nase und Sturm in der Hose!"
- -- Falco, "Qué Pasa Hombre"
Eines der Teilprojekte meines
Hauptbetätigungsfeldes außerhalb der Firma ist ein Programm namens "Notorious" mit der ich die Datenbank der
FreeDB durchsuchen kann. Die FreeDB ist eine von Internet-Usern zusammengetragene Liste der Titellisten von CDs. Was da an Daten mittlerweile zusammengekommen ist, ist eine Menge: fast 5GB. Ein Beispiel für die Suche wäre zum Beispiel: ich will wissen, auf welcher CD die Maxi-Version des Titels "Maneater" von Hall & Oates drauf ist. Also suchte ich nach "Maneater" und einer Spielzeit von mindestens fünf Minuten. Die Suche war ein voller Erfolg, mittlerweile stehen zwei verschiedene CDs mit dem Titel in meiner Sammlung.
Normalerweile verwende ich für solche Applikationen gerne die Datenbank
SQLite. Sie wird von Qt von Haus aus unterstützt, und kommt ohne eine weitere Einrichtung zurecht. Leider ist SQLite bei den Datenmenge (zumindest so, wie ich die Daten organisiert habe) nicht in der Lage, wirklich performant darin zu suchen. Das Aufbauen der Datenbank ist noch zeitintensiver. Im Moment rettet mich da noch mein Quad Core Rechner, aber auf durchschnittlicher Hardware ist das definitiv kein Spaß mehr. Deshalb muss dort eine tief greifende Änderung her.
Die Frage ist nun, wie diese Änderung aussehen sollte. Ich schwanke noch zwischen mehreren Optionen. Eine Option ist, eine andere SQL-Datenbank zu nehmen.
MySQL und
PostgreSQL sind dort die Favoriten, da diese von Qt unterstützt werden, und für alle Plattformen verfügbar sind. Eventuell programmiere ich die Schnittstellen auch als Plugin, so dass diese auch leicht austauschbar sind. Der Aufwand ist aber nicht zu verachten, da ich dann auch MySQL und PostgreSQL auf meinen Entwicklungssystemen für Linux, Windows und Mac OS X installieren muss, schon allein der Tests wegen.
Außerdem bleibt die Frage, ob ich die Daten besser organisieren kann. Nein, ich sollte es besser so formulieren: es bleibt die Frage,
wie ich die Daten besser organisieren kann. Im Moment sieht meine Tabelle so aus:
CREATE TABLE freedb( category VARCHAR, id VARCHAR, track INT, title VARCHAR, playtime INT, ext VARCHAR, PRIMARY KEY( category, id, track) );
Erster Ansatzpunkt wird dabei "category". Das ist momentan ein Textfeld, welches eine der elf Kategorien der Datenbank abbildet: data, rock, classic, raggae, ... . Das kann ich entweder als eine Zahl abbilden, oder gleich für jede Kategorie eine eigene Tabelle anlegen, um so die Daten besser zu aufzuteilen. Die "id" ist ein 32-Bit Hex-Wert, und könnte ebenso in INT-Format übertragen werden, da aber SQLite jedes Datum intern als String verwaltet, speichere ich einfach den Hex-Wert als String ab. "title" und "playtime" sind die eigentlichen Daten, in denen ich suchen möchte, da kann man vermutlich nicht viel dran optimieren. Wie sieht nun aber ein optimaler Datenbankaufbau aus? Optimal im Sinne von "da kann man schnell drin suchen", aber auch "die Datenbank kann man schnell aufbauen".
Und überhaupt: welche Datenbank sollte ich überhaupt nehmen, und wie sie konfigurieren? Sollte es überhaupt eine SQL-Datenbank sein? Eine weitere und komplette unterschiedliche Alternative könnte ein LDAP-Server statt der SQL-Datenbank sein. Allerdings habe ich keine Ahnung was dafür alles nötig ist und ob man unter LDAP performant in den Daten suchen kann.
Für Vorschläge und Anregungen, sei es als Kommentar, oder als Email wäre ich echt dankbar.
Nachtrag (19.März 2010):
Ich wurde per E-Mail gebeten, noch etwas mehr in die Details zu gehen. Deshalb hier noch ein paar Infos, wie ich die Datenbank aufbaue. Die FreeDB zum Runterladen ist ein tar-Archiv. Die Dateien sehen so aus:
$ cat data/21037703
# xmcd
#
# Track frame offsets:
# 150
# 21592
# 47662
#
# Disc length: 889 seconds
#
# Revision: 4
# Processed by: cddbd v1.5.2PL0 Copyright (c) Steve Scherf et al.
# Submitted via: ExactAudioCopy v0.95b2
#
DISCID=21037703
DTITLE=Black Sabbath / Feels Good To Me
DYEAR=1990
DGENRE=Heavy Metal
TTITLE0=Feels Good To Me (edit)
TTITLE1=Feels Good To Me
TTITLE2=Paranoid (live)
EXTD=Recorded live in Germany on the Hell On Stage World Tour YEAR: 19
EXTD=99
EXTT0=
EXTT1=
EXTT2=
PLAYORDER=
Anstelle nun das Archiv auszupacken, parse ich Datenstrom im tar-Archiv direkt. Ich habe mir quasi eine Art Mini-untar gebaut. Die Datei wird dann analysiert und heraus kommen dann folgende SQL Anweisungen:
INSERT INTO "freedb" VALUES('data','21037703',0,'Black Sabbath / Feels Good To Me',66675,'Recorded live in Germany on the Hell On Stage World Tour YEAR: 1999');
INSERT INTO "freedb" VALUES('data','21037703',1,'Feels Good To Me (edit)',21442,'');
INSERT INTO "freedb" VALUES('data','21037703',2,'Feels Good To Me',26070,'');
INSERT INTO "freedb" VALUES('data','21037703',3,'Paranoid (live)',19013,'');
Ich bin also in der Wahl meines Datenbank-Schemas komplett frei, und kann diese so aufbauen, wie sie am performantesten ist.
Die Suche innerhalb des Programms geht in zwei Schritten von statten, zuerst wird nach dem einem Titel (in diesem Fall zum Beispiel "*Paranoid*") mit eventueller Spielzeitangabe wie "mehr als 2 Minuten" gesucht. (In der Datenbank ist die Zeiteinheit 75stel-Sekunden, das ist ein Sektor auf der CD.) Wurde dann etwas gefunden wird nach der Kombination "data"/"21037703" gesucht, um den kompletten Inhalt der CD zu bekommen.
Kommentare
http://lucene.apache.org/
bzw. in letzter Zeit mehr mit dem Solr-Server, der für deine Zwecke wohl nicht das richtige ist. Aber Lucene könnte etwas sein, wobei ich nichts über die Qt/C++-Anbindung weiß, ich entwickle in Java. Aber größere Datenmengen schnell durchsuchen, das kann Lucene gut, und die Lernkurve ist nicht allzu steil. Deutlich weniger komplex als SQL-DBs. Aber ob es das richtige für deinen Zweck ist, ich weiß es nicht. Lucene ist optimiert fürs Suchen, Datenhaltung ist eher zweite Priorität, wenn überhaupt.
ggf könntest du über title auch einen soundex-hash bilden und den per index oder fulltext-index durchsuchen.