Unbefriedigende Ausgangslage
Die Aktualisierung von Katalogen in der KUG Recherche-Infrastruktur (Kölner UniversitätsGesamtkatalog) beruht seit jeher auf der Einspielung einer Komplettlieferung der Daten eines jeden Katalogs.
Auf diese Weise werden Tag für Tag mehr als 150 Kataloge mit ihren Daten eingespielt, der überwiegende Restbestand an Katalogen wird wöchentlich aktualisiert und einige wenige (z.B. Digitalisate aus der OpenLibrary) in längeren Abständen.
Obwohl die Aktualisierung in drei Threads parallel abläuft, sind die Datenänderungen des Vortags inzwischen in der Regel erst ab 15 – 16 Uhr des Folgetags für den Endnutzer recherchierbar.
Durch die Migration von Institutsbeständen in den USB-Katalog und zusätzliche Anreicherungen ist allein dessen Aktualisierungszeit von früher durchschnittlich 10 Stunden auf aktuell mehr als 15 Stunden angewachsen.
Aus diesem Grund haben wir nach Möglichkeiten gesucht, bei der nur Titeländerungen (gelöscht, neu angelegt, oder geändert) in einem Recherche-Katalog Einzug in dessen Aktualisierungsprozess halten. Folgende Anforderungen sollten erfüllt werden:
- Wegen der Heterogenität der Daten-Quellen muß eine systemunabhängige Lösung gefunden werden, die auf alle Kataloge anwendbar ist. Es reicht z.B. nicht, wenn in einigen Datenquellen das Bibliothekssystem die Titel-IDs der Änderungen vorbildlich liefert, in anderen aber keine solche Funktionalität bereitgestellt wird. Die Programmierung verschiedener inkrementeller Aktualisierungsroutinen für verschiedene Daten-Quellen ist nicht zielführend.
- Eine Lösung sollte sich möglichst nahtlos in die bestehenden Phasen des Ablaufs einer Aktualisierung integrieren und diese unangetastet lassen. Das ist umso wichtiger, da u.a. Katalog-Anreicherungen und katalogspezifische „Sonderbehandlungen“ Teil dieses Ablaufs sind. Daher sollen weiterhin Gesamtlieferungen aller vorhanden Katalogdaten zwingende Voraussetzung auch für eine inkrementelle Aktualisierung sein.
Die grundsätzliche Strategie ist daher:
- Nehme eine neue Gesamtlieferung,
- bestimme anhand des bisherigen Katalogbestands den Teilbestand der Datensätze, die für eine Aktualisierung überhaupt relevant sind und
- Aktualisiere nur diese Datensätze anstelle aller.
Umsetzung der inkrementellen Aktualisierung
Eine wesentliche Voraussetzung für unsere triviale Umzusetzung eines inkrementellen Updates wurde bei den Änderungen der letzten OpenBib-Versionen geschaffen – die Umstellung des MAB2-basierten Metadaten-Formats, in das alle gelieferten heterogenen Daten vereinheitlicht werden, auf eine Kodierung in JSON (JavaScript Object Notation).
Jeder Normdatensatz liegt in den Dateien des Metadaten-Formats (meta.title.gz, meta.person.gz, meta.corporatebody.gz meta.classification.gz, meta.subject.gz und meta.holding.gz) als eine Zeile in JSON-Kodierung vor, z.B. :
{„fields“:{„1209“:[{„content“:“UNummer“,“subfield“:““,“mult“:“001″}],“0412″:[{„content“:“Ebering“,“subfield“:““,“mult“:“001″}],“0435″:[{„content“:“8¹“,“subfield“:““,“mult“:“001″}],“0009″:[{„content“:“HBZ“,“subfield“:““,“mult“:“001″}],“4400″:[{„content“:“lendable“,“subfield“:““,“mult“:1}],“0331″:[{„content“:“Experimentelle Bestimmung und thermodynamische Berechnung der Dampfdrucke von Toluol, Naphthalin und Benzol“,“subfield“:““,“mult“:“001″}],“0038″:[{„content“:“y“,“subfield“:““,“mult“:“001″}],“0519″:[{„content“:“Berlin, Univ., Diss., 1909″,“subfield“:““,“mult“:“001″}],“0027″:[{„content“:“V“,“subfield“:““,“mult“:1}],“0003″:[{„content“:“02.05.2008″,“subfield“:““,“mult“:1}],“0010″:[{„content“:“TT002403298″,“subfield“:““,“mult“:“001″}],“0011″:[{„content“:“TL002408293″,“subfield“:““,“mult“:“001″}],“0100″:[{„supplement“:““,“id“:“1400548″,“subfield“:““,“mult“:“001″}],“0002″:[{„content“:“23.04.2008″,“subfield“:““,“mult“:1}],“0015″:[{„content“:“ger“,“subfield“:““,“mult“:“001″}],“0800″:[{„content“:“a“,“subfield“:““,“mult“:“001″}],“0425″:[{„content“:“1909″,“subfield“:““,“mult“:“001″}],“0359″:[{„content“:“von Jonathan Tong Barker“,“subfield“:““,“mult“:“001″}],“0433″:[{„content“:“39 S.“,“subfield“:““,“mult“:“001″}],“0036″:[{„content“:“m“,“subfield“:““,“mult“:“001″}],“0554″:[{„content“:“U 09.136″,“subfield“:““,“mult“:“001″}],“0410″:[{„content“:“Berlin“,“subfield“:““,“mult“:“001″}]},“id“:“6096939″}
Damit können wir für jeden Datensatz sehr einfach mit kryptographischen Hashverfahren wie SHA1 oder MD5 einen Fingerabdruck, hier z.B. aa12433a662965b80f706fa82748e4ba generieren.
Zusätzlich wurden die Normdaten-Tabellen in den zugehörigen PostgreSQL-Datenbanken (title, person, corporatebody, classification, subject und holding) um eine Spalte „import_hash“ erweitert, in die beim Einladen der zuvor aus der Einladedatei erzeugte Hashwert wandert.
Auf diese Weise ist es nun sehr einfach möglich, aus den IDs und Hashwerten in der Datenbank und denen einer neuen Lieferung punktgenau die zwischen beiden Datenständen erfolgten Änderungen zu bestimmen:
- Ein Datensatz muß in der Datenbank gelöscht werden, wenn seine ID nicht mehr in der neuen Datenlieferung vorkommt
- Ein Datensatz muß neu in die Datenbank aufgenommen werden, wenn seine ID aus der neuen Datenlieferung noch nicht in der Datenbank vorhanden ist
- Ein Datensatz muß in der Datenbank geändert werden, wenn seine ID sowohl in der Datenbank wie auch der neuen Datenlieferung vorhanden ist, die Hashwerte sich aber unterscheiden
- Ein Datensatz kann ignoriert werden, wenn seine ID sowohl in der Datenbank wie auch der neuen Datenlieferung vorhanden ist, aber die Hashwerte gleich sind
Diesen Entscheidungsprozessen geht ein Scan der IDs und Hashwerte aus der Datenbank und der neuen Datenlieferung voraus, dessen Ergebnis in einer Datenstruktur status_map festgehalten wird. Aus dieser Datenstruktur kann dann beim regulären Umwandeln der Metadaten mittels meta2sql.pl sehr einfach mit einer Methode analyze_status_map die notwendige Aktion bestimmt werden.
In der konkreten Umsetzung werden diese Aktionen noch weiter vereinfacht, indem Datensatzänderungen als Datensatzlöschung mit nachfolgender Erzeugung eines neuen Datensatzes modelliert werden. Dadurch können auch schnelle Bulk-Insertverfahren auf Seite der PostgreSQL-Datenbank genutzt werden.
Zuerst werden daher alle relevanten Zeilen aus den beteiligten Tabellen (per delete) gelöscht (gelöschte und geänderte Datensätze) und danach alle neuen Zeilen (neue und geänderte Datensätze) eingeladen (per bulk COPY).
Nach dem Scan werden die IDs der zu löschenden und neu anzulegenden Datensätze zusätzlich in zwei eigenen Dateien mit den Suffixen .delete und .insert abgelegt, z.B. title.delete und title.insert. Diese Dateien sind hilfreich, da sie sowohl für eine weitere Beschleunigung des Aktualisierungsprozesses verwendet werden können, als auch für nachgelagerte Programme mit einer eigenen inkrementellen Aktualisierung nachnutzbar sind.
- Für eine Beschleunigung der datenbankseitigen delete-Aktion in den verschiedenen Tabellen werden die IDs der zu löschenden Datensätze per bulk COPY in eine eigene temporäre Tabelle title_delete geladen, anhand der dann sehr schnell eine Löschung relevanter Zeilen in anderen Tabellen durchgeführt werden kann, z.B. mit
DELETE FROM title_title WHERE source_titleid IN (select id from title_delete);
- Mit dem Programm update_all_titles_table.pl wird anhand verschiedener Kriterien (ISBN13, BibKey, ISSN, WorkKey) zentral in unserer Anreicherungsdatenbank festgehalten, welche Titel-ID in welchem Katalog welche ISBN13, ISSN usw. besitzt. Mit diesen Informationen werden Funktionen wie „Gleicher Titel in anderen Katalogen“ oder „Andere Ausgaben des Titels“ für den Endnutzer umgesetzt. Ebenso können für Aussonderungsaktionen von Institutsbibliotheken so sehr einfach Titelabgleiche zwischen verschiedenen Katalogen durchgeführt werden. Daher gehört zu einer Aktualisierung des Datenbestandes eines Katalogs auch immer die Aktualisierung der entsprechenden zentralen Tabellen (all_titles_by_isbn, all_titles_by_bibkey usw.). Bisher wurden diese Informationen bei der Aktualisierung eines Katalogs für diesen jeweils komplett gelöscht und danach mit dem neuen Stand wieder eingespielt. Auch hier kann nun sehr einfach mithilfe der beiden Titel-ID-Dateien title.delete und title.insert zielgenau nur noch der sich tatsächlich geänderte Teilbestand aktualisiert werden.
Neben den Einladedateien für die PostgreSQL-Datenbank eines Kataloges erzeugt das um die inkrementelle Aktualisierung erweiterte Programm meta2sql.pl auch Einladedateien für den zugehörigen Xapian-Suchmaschinenindex.
Dementsprechend musste auch das Aktualisierungsprogramm für den Suchindex file2xapian.pl um die inkrementelle Änderung nur einzelner Dokumente erweitert werden. Auch hier wurde bisher ein komplett neuer Index erstellt, der dann den bisherigen ersetzte.
Vorher – Nachher
Welche Änderungen haben sich nun durch die Einführung inkrementeller Updates ergeben. Als Beispiel bietet sich der Katalog der USB-Köln mit knapp 3.35 Millionen Titelnachweisen an.
Bisher dauerte die Komplett-Aktualisierung des Katalogs 15:19:26 Stunden. Wesentliche Anteile sind:
- 15596.5 Sekunden für die Erzeugung der Einladedateien für PostgreSQL-Datenbank und Xapian-Suchmaschinenindex
- 6193.86 Sekunden für das Einladen der Daten in die PostgreSQL-Datenbank
- 17432.3 Sekunden für das Einladen der Daten in den Xapian-Suchmaschinenindex
- 8580.2 Sekunden für die Aktualisierung der zentralen Daten mit update_all_titles_table.pl
Bei der inkrementellen Aktualisierung des Katalogs kommen wir mit 02:41:18 Stunden aus. Die entsprechenden Anteile sind hier:
- 1613.76 Sekunden für die Erzeugung der Einladedateien für PostgreSQL-Datenbank und Xapian-Suchmaschinenindex
- 1220.33 Sekunden für das Einladen der Daten in die PostgreSQL-Datenbank
- 655.64 Sekunden für das Einladen der Daten in den Xapian-Suchmaschinenindex
- 274.3 Sekunden für die Aktualisierung der zentralen Daten mit update_all_titles_table.pl
Nahezu konstant bleiben bei diesem Katalog die durchgeführten Schritte der Vorverarbeitung mittels Plugin post_unpack.pl. Hier werden u.a. Teilbestände markiert, so dass sie später einfach geschlossen recherchiert und facettiert werden können. Dazu gehören z.B. Teilbestände einzelner Fach- oder Institutsbibliotheken im USB-Katalog mit anderem Standort ebenso wie thematische Teilbestände (Kunst).
Diese Vorverarbeitungsschritte liegen sowohl bei kompletter wie auch inkrementeller Aktualisierung bei knapp 50 Minuten und gehen zwar in die Gesamtlaufzeit ein, sind aber nicht – wie einige andere auch – gesondert aufgeführt.
Für die Routine-Aktualisierung von Katalogen in der KUG Recherche-Infrastruktur wird wochentags inzwischen nur noch die inkrementelle Variante verwendet. Am Wochenende wird – mit Katalogstand Freitag 18 Uhr – weiterhin komplett aktualisiert.
In der Regel sind so wochentags Datenänderungen des Vortags vor 6 Uhr morgens des Folgetages recherchierbar. Die Erweiterung der Aktualisierungsprogramme um ein inkrementelles Update hat sich also gelohnt.