Solr-gestützte ISFDB – Teil #3: Dokumentenmodellierung
Dies ist Teil 3 einer (nicht enden wollenden?) Artikelserie über das Indizieren und Durchsuchen der ISFDB.org-Daten mit Solr. Als wir…
Dies ist Teil 3 einer (nicht enden wollenden?) Artikelserie über das Indizieren und Durchsuchen der ISFDB.org-Daten mit Solr.
Als wir am 28. Januar aufhörten, hatte ich Konfigurationen, die es mir ermöglichten, mit dem DataImportHandler einen sehr einfachen Index aller Titel+Autoren-Paare in der ISFDB zu erstellen, der in sinnvolle Felder mit nützlichen Datentypen indexiert. Das Ziel am vergangenen Freitag (als ich es geschafft habe, ein wenig Arbeit in diesen Index zu quetschen, aber erst heute dazu gekommen bin, darüber zu bloggen) war es, die „Dokumentenmodellierung“ des Index zu verbessern, so dass Abfragen verwendet werden können, um sinnvolle Fragen zu „Titeln“ zu beantworten.
(Wenn Sie zu Hause mitarbeiten möchten, können Sie den Code auf github auschecken. Ich beginne mit dem blog_2-Tag und werde im weiteren Verlauf des Artikels auf bestimmte Commits verweisen, in denen ich etwas geändert habe, bis hin zum blog_3-Tag, der das Endergebnis dieses Artikels enthält).
Was bedeutet „Dokumentenmodellierung“?
„Ich verwende den Begriff „Dokumentenmodellierung“, weil Sie im Gegensatz zur traditionellen RDBMS- oder OO-Datenmodellierung bei der Verwendung einer IR-Engine wie Solr „flach“ denken müssen. Vollständige Beziehungen müssen in einzelne „Dokumente“ zerlegt werden, die die Grundlage für alle Aktionen bilden.
Am Ende des Blogs von letzter Woche habe ich einige Abfragen erwähnt, die wir mit den Daten, die wir hatten, durchführen konnten…
- Alle Datensätze, in denen der Nachname des Autors smith lautet
- Alle Datensätze für Romane von in Paris geborenen Autoren
- Aufzeichnungen über Titel mit „Raum“ im Namen, mit Facettenzählungen basierend auf der Art des Werks
- Eine Aufschlüsselung, die zeigt, wie viele Romane „Weltraum“ vs. „Roboter“ vs. „Roboter“ in ihren Titeln enthalten
Der wichtigste Teil dieser Abfragebeschreibungen ist der Begriff „Datensatz“ … was ich damit meinte, ist, dass aufgrund der Art und Weise, wie die Daten indiziert wurden, jedes Dokument in unserem Index einem „Datensatz“ eines Paares aus Titel und Autor entsprach – was ziemlich willkürlich ist. Das ist nicht die Art von Information, nach der die meisten Leute suchen. Die Leute wollen nach „Büchern“ oder „Personen“ suchen – nicht nach „Instanzen, in denen eine Person Autor eines Buches war“.
Heute werden wir also unseren Index so anpassen, dass jedes Dokument einen „Titel“ modelliert und Informationen über alle Autoren enthält, die an dem Dokument mitgearbeitet haben.
Erste Schritte
Zu Beginn habe ich mir die ISFDB.org DB Schema Dokumentation angesehen. (Es sagt viel über Solr aus, dass dies wirklich das erste Mal war, dass ich mir eine Dokumentation zu den Tabellen, die ich indizieren wollte, ansehen musste). Dabei bin ich auf einige Informationen gestoßen, die ich mir zunutze gemacht habe…
- Durch die Einschränkung ca_status=1 in unserer DB-Abfrage eliminieren wir Rezensionen und erhalten nur die tatsächlichen Autoren der Titel.
- überprüft, dass title_ctl ein falsches Feld ist
Mit diesen Änderungen im Hinterkopf war das erste, was ich tun musste, um bei den Konfigurationen voranzukommen, die explizite Angabe der Felder, die ich in unserem SQL haben wollte, damit ich den Überblick darüber behalten konnte, was von woher kam, und die Felder, die ich bereits ignoriert hatte, komplett überspringen konnte.
Verschachtelte Entitäten
Als Nächstes stellten wir unsere oberste „Entität“ in der DIH-Konfiguration auf „Titel“ um und fügten eine „verschachtelte Entität“ hinzu, die den „Autor“-Daten entspricht. Die Verwendung von verschachtelten Entitäten wie dieser ermöglicht eine Abfrage, die die wichtigsten Details zu jeder Zeile („Titel“) abruft, mit einer Unterabfrage, die mehrere Werte für mehrwertige Felder (die „Autor“-bezogenen Felder) zurückgibt.
Die Verwendung von verschachtelten Entitäten ist viel langsamer (~6,5 Minuten auf meinem Laptop gegenüber ~2 Minuten in der alten Version), aber das liegt nur daran, dass wir viel mehr SQL-Abfragen ausführen müssen (600k+ SQL-Abfragen anstelle von 1) – das liegt in der Natur des DB-Datenmodells. Wenn das Datenmodell den Begriff eines „primären“ Autors hätte, dann könnten wir diesen in unseren Haupt-Select für die Entität „title“ einbeziehen, und die meisten Abfragen für die Unterentität „title_author“ wären dann No-ops. (Ich bin mir allerdings nicht sicher, ob dies tatsächlich schneller wäre)
Der Vorteil ist, dass wir jetzt ein einzelnes Dokument pro „Titel“ mit mehrwertigen Feldern haben, die die Autorendetails enthalten. Da diese Dokumente titelzentriert sind, entferne ich einige der Autorenfelder, da sie keinen wirklichen Mehrwert bieten. (Ich werde sie wieder hinzufügen, wenn wir auch autorenbezogene Dokumente in unseren Index aufnehmen)
Fehlanzeige: DIH und mehrere Werte für einfach bewertete Felder
Bei meinen Tests habe ich etwas Interessantes über DIH entdeckt, das ich vorher nicht kannte. Wenn Sie DIH so konfigurieren, dass es mehrere Werte für ein Feld erzeugt (wie alle author_*-Felder in meiner aktuellen isfdb-dih.xml), aber einige dieser Felder in Ihrem Schema multiValued=“false“ sind (ich habe vergessen, dies zu author_canonical hinzuzufügen), verwirft DIH stillschweigend die Duplikate für Sie und gibt Ihnen nur einen Wert. Ich hätte erwartet, dass es zu einem Fehler kommt (sonst hätte ich meinen Fehler vor der letzten Übertragung bemerkt), aber das tut es nicht – man lernt aus seinen Fehlern(und behebt den Fehler in der schema.xml).
Die Dinge beschleunigen?
An diesem Punkt habe ich versucht, den CachedSqlEntityProcessor zu meiner Unterentität hinzuzufügen, aber das hat die Sache nicht beschleunigt. Im Nachhinein war dies angesichts der Anzahl der Autoren nicht allzu überraschend, aber dann wurde mir klar, dass durch die Verwendung von canonical_authors in der Sql für die verschachtelte Entität natürlich jeder Select eindeutig sein würde.
Dann bemerkte ich die Option von CachedSqlEntityProcessor, alle Zeilen einer Entität als Teil einer einzigen Upfront-Abfrage in den Speicher zu laden. Das ist eine Funktion, die ich noch nicht kannte und die sich für den Umgang mit Autoren als sehr nützlich erwies (vorausgesetzt, Sie haben den nötigen Arbeitsspeicher). Der Trick bestand darin, canonical_authors aus der Entität auszulagern (so dass wir nur eine Zeile pro Autor haben, nicht eine pro author_title), was zu einer dreifach verschachtelten Entität führt, die nur 3 DB SQL-Aufrufe benötigt, um alle Daten zu erhalten.
Dadurch konnte die Indizierungszeit auf nur ~70 Sekunden gesenkt werden. Das ist weitaus besser als ich erwartet hatte (ich dachte mir, dass es annähernd so schnell sein könnte wie der Single Select, aber ich hatte nicht erwartet, dass es schneller sein würde). Die Verwendung von CachedSqlEntityProcessor ist nicht in allen Situationen hilfreich (es hängt wirklich von der Menge der Daten ab, die Sie zwischenspeichern wollen, und davon, wie viel RAM Sie zur Verfügung haben), aber in diesem Fall hat es sich als großartig erwiesen.
Fazit (vorläufig)
Und damit ist diese letzte Folge mit dem blog_3-Tag abgeschlossen. Abfragen wie die, die ich letzte Woche erwähnt habe, liefern uns alle Ergebnisse, die tatsächlich etwas Interessantes über „Titel“ in der ISFDB aussagen…
- Alle Titel von einem Autor, dessen Name „Smith“ enthält
- Titel mit „Raum“ in ihrem Namen, mit Facettenzählungen basierend auf der Art der Arbeit
- Eine Aufschlüsselung, die zeigt, wie viele Romane „Weltraum“ vs. „Roboter“ vs. „Roboter“ in ihren Titeln enthalten
Schauen Sie Ende dieser Woche wieder vorbei, wenn ich plane, „autorenorientierte“ Dokumente zu unserem Dokumentenmodell hinzuzufügen, so dass Benutzer nach Titeln oder Autoren suchen können und trotzdem aussagekräftige Ergebnisse erhalten.