Vorwort: wieso ein Blog zu PHP, Solr und Lucene?

Wieso ein Blog zu PHP, Solr und Lucene?
Gegenstand und Ausgangspunkt all unserer Aktivitäten auf diesem Gebiet war ein Projekt um ein Nachrichtenportal und die Aufgabe, Recherchen und Analysen im Nachrichtenbestand von über 10 Million News performant zu handeln. Die MySQL Volltextsuche kam da schnell an Ihre grenzen, Oracle war keine Alternative.
Es reifte also die Frage, wie können andere (etwa die Internetsuchmaschiene google) immense Datenmengen spielend handeln?
Wir lösten den MySQL volltext mit Lucene ab. Der Performancegewinn war dramatisch. Suchen im Datenbestand, die vorher über 10 Sekunden dauerten, brauchen mittels Lucene und Solr nur selten mehr als 20ms!
Eine neue Welt tat sich auf, die es zu erobern galt und schnell fiel auf, dass deutschsprachige Seiten zum Thema Mangelware sind. Dies soll sich mit diesem Blog ein wenig ändern.

Sie haben Fragen zu Solr/Lucene/PHP? Schreiben sie uns einen Kommentar!

Donnerstag, 18. September 2014

Suchergebnis verbessern: Teile einese Textes unterschiedlich gewichten

Seit google wissen wir: kein Mensch möchte bei einer Suche/Volltextsuche auf die 2. Ergebnisseite blättern.
So etwa ist die Vorgabe durch den Anwender.
Der Knackpunkt neben validen Suchergebnissen ist also eine möglichst gute Relevanzsortierung.
Glücklicher Weise funktioniert die Relevanzsortierung bei Solr schon sehr gut. Dennoch gibt es je nach Dokumentenart und -inhalt Optimierungspotential.

In unserem Fall werden informelle Volltexte verarbeitet: Nachrichten. Diese haben die Natur, dass in den ersten Zeilen meist Zusammenfassungen, Kontextinformationen oder expemplarische Informationen zur Nachricht selber stehen.
Die ersten Zeilen eines Dokumentes sind also meist besonders inhaltsreich und relevant
Aus diesem Grund bossten wir die ersten N Zeichen eines jeden Dokumentes besonders. Oder anders Gesagt: Teile des eines Textes werden unterschiedlich gewichtet.

Das boosten bzw. höhere Gewichten einzelner Textabschnitte oder Zeilen in Solr funktioniert über einen Trick. Beim Import der Daten aus unserer MySQL Tabelle mittels Data-Import-Handler (DIH) erzeugen wir eine virtuelle Spalte. Diese zusätzliche Spalte befüllen wir mit den ersten N Zeichen des eigentlichen Volltextes. In der data-config.xml des DIH sieht das dann exemplarisch wie folgt aus:

<entity name="tabelle_news" pk="LFNR" 
        query="SELECT *,
                SUBSTRING(TEXT,1,500-CHAR_LENGTH(SUBSTRING_INDEX(SUBSTRING(TEXT,1,500),' ',-1))) 
                AS TEXT_SNIPPET
                FROM tabelle_news
                WHERE '${dataimporter.request.clean}' != 'false'
                           OR LAST_MODIFIED &gt;= '${dataimporter.last_index_time}' - INTERVAL 5 MINUTE">
</entity>
In der Konfiguration des Data-Import-Handler oben wird unmittelbar während des Imports ein maximal 500 Zeichen langer Text Schnipsel aus den ersten Zeichen des Dokumenten-Textes gennerriert und als neues Feld an Solr weiter gereicht. Wichtig ist, nicht blind nach 500 Zeichen abzuschneiden, sondern bereits am Ende des letzten Wortes innerhalb der 500 Zeichen!

Dieses Feld sollte natürlich in der Schema-Datei (schema.xml) entsprechend vorhanden sein, idealer Weise vom gleichen Typ, wie das Volltextfeld.

Wichtig ist, den Textschnipsel auch bei der Suche zu würdigen.
Dazu wird die Datei (solrconfig.xml) entsprechend angepasst.

In unserem Fall kommt der edismax SearchHandler zum Einsatz. Hier kann man explizit angeben, in welchen Feldern er suchen soll und wie Stark die einzelnen Felder gewichtet werden sollen. Exemplarisch könnte der Eintrag wie folgt aussehen:

<requestHandler name="/select" class="solr.SearchHandler" default="true">
     <lst name="defaults">
       <str name="defType">edismax</str>
       <float name="tie">0.01</float>
       <bool name="tv">true</bool>
       <str name="qf">
          
AGENTUR^10 UEBSCHRIFT^5.5 TEXT^1.5 THEMA TEXT-EXAKT^7 TEXT_SNIPPET
       </str>
       <str name="q.alt">*:*</str>
       <str name="pf">
          AGENTUR^10 UEBSCHRIFT^5.0 TEXT^1.5 TEXT-EXAKT^7 TEXT_SNIPPET
       </str>

[...]
Startet ein Anwender eine Suche, so sucht Solr die Informationen in verschiedenen Feldern der Dokumente und gewichtet das Ergebnis abhängig davon, in welchem Feld der gesuchte Begriff auftaucht.
Wichtig ist, dass hier das Feld TEXT_SNIPPET überhaupt erwähnt wird, damit es in der Relevanzberechnung berücksichtigt wird. Je nach Anwendungsfall kann man diesen Bereich natürlich auch noch boosten.
In jedem Fall aber wird nun der erste Teil eines Volltextes/Dokumentes stärker berücksichtigt/gewichtet als der Rest des Dokumentes/Textes.