Hervorhebende Textmarker-Gedanken
Ich habe einige Highlighter-Arbeiten zu erledigen (grundlegende Unterstützung für die Hervorhebung von ConstantScoreQuerys), und so habe ich den Highlighter im…
Ich habe einige Highlighter-Arbeiten zu erledigen (grundlegende Unterstützung für die Hervorhebung von ConstantScoreQuerys), und so habe ich den Highlighter im Kopf…
Die Geschichte…
Der erste Lucene Highlighter wurde von Mark Harwood, einem langjährigen Lucene Contribitter und PMC-Mitglied, geschrieben und zu Lucene beigetragen. Mark hat eine schöne, robuste, erweiterbare API und eine Handvoll Standardimplementierungen für die API entwickelt. Es war eine sehr solide Highlighter-Implementierung, die sich gegenüber vielen komplizierten Analyzern und Filtern gut behauptet hat. Eine Vielzahl von Autoren hat den Code im Laufe der Jahre bereichert (Bugs beseitigt und Verbesserungen vorgenommen), und der Highlighter ist heute ziemlich leistungsfähig und wird stark genutzt.
Der Lucene contrib Highlighter wurde mit dem Schwerpunkt auf der Erzeugung von Textfragmenten entwickelt. Damit können Sie auf einfache Weise Ansichten vom Typ „Schlüsselwörter im Kontext“ erzeugen (z. B. die Ergebnisliste Ihrer bevorzugten Suchmaschine). Schließlich wurde der NullFragmenter hinzugefügt, mit dem Sie auch ein komplettes Dokument hervorheben können (Sie hätten die API verwenden können, um Ihren eigenen NullFragmenter zu schreiben, bevor Lucene ihn hinzufügte – eine der schönen Seiten der relativ anpassbaren API des Highlighters).
Scoring und Hervorhebung…
Der Highlighter arbeitet mit einem TokenStream und einer Abfrage. Ein TokenStream ist genau so, wie es sich anhört: ein Strom von Token – oder sogar Begriffen, wenn das einfacher ist – mit möglicherweise angehängten zusätzlichen Metadaten (Position, Offsets im Originaltext usw.). Ein Analyzer und ein Dokument erzeugen einen TokenStream – wenden Sie den Analyzer auf den Text des Dokuments an, und die Token kommen heraus. Durch den Vergleich der Token aus der Abfrage mit den Token aus dem Dokument kann der Highlighter erkennen, welche Token hervorgehoben werden sollten (termFromDoc==termFromQuery? Highlight!). Der Highlighter arbeitet, indem er die Token aus dem Dokument nacheinander an einen Scorer weiterleitet. Der Scorer weist dem Token eine Punktzahl zu. Der QueryScorer vergibt die Punktzahl auf der Grundlage, ob das Token mit einem Token in der Abfrage übereinstimmt. Anschließend werden Fragmente generiert und anhand der zugrunde liegenden Token-Bewertungen bewertet. In der Regel kann der Token-Score nur 0 oder 1 sein, aber Sie können auch einen Gradienten hervorheben, indem Sie den Bereich der Scores erweitern (wenn Sie einen IndexReader an QueryScorer übergeben, verwendet er Term-Index-Statistiken, um den Score auf der Grundlage dieser Statistiken zu ändern). Schließlich fügt eine steckbare Formatter-Implementierung den hervorgehobenen Text ein (anhand der Punktzahl wird entschieden, ob und welcher Text eingefügt wird).
Abrufen eines TokenStreams für ein Dokument…
Leider speichert der Index den TokenStream für ein Dokument nicht. Wenn es also an der Zeit ist, zu markieren, muss der Benutzer einen gültigen TokenStream für den Text des Dokuments beschaffen. In der Regel bedeutet dies, dass Sie den Originaltext des Dokuments durch den Analyzer schieben müssen, den Sie für die Indizierung des Dokuments verwendet haben. Wenn Sie jedoch Termvektoren in Ihrem Index gespeichert haben, können die Positions- und/oder Offset-Informationen verwendet werden, um den TokenStream aus den Informationen im Index zu rekonstruieren. Besonders bei großen Dokumenten kann dies sehr viel schneller sein. Die Klasse TokenSources im Highlighter-Paket baut einen TokenStream für Sie auf, wobei die beste Methode verwendet wird, je nachdem, ob Termvektoren verfügbar sind oder nicht.
SpanScorer – Hinzufügen einer positionsabhängigen Hervorhebung…
Vor ein paar Jahren habe ich mich dafür interessiert, den Highlighter um Positionsunterstützung zu erweitern. Die QueryScorer-Implementierung prüft lediglich, ob Token aus der Abfrage mit Token aus dem Dokument übereinstimmen, und berücksichtigt nicht die Position der Token. Das Ergebnis ist, dass bei der Verwendung einer PhraseQuery nicht nur die Phrase hervorgehoben wird, sondern jeder Begriff in der Phrase überall hervorgehoben wird, wo er vorkommt. In der Vergangenheit gab es bereits Versuche, die Hervorhebung von PhraseQuery zu unterstützen, aber nicht in einer Weise, die das aktuelle Highlighter-Framework nutzte, und nicht in einer Weise, die die anderen Positionsabfragen (SpanQuery, MultiPhraseQuery usw.) unterstützte. Ich wollte so gut wie vollständige Highlighting-Unterstützung sowie all die Vorzüge, die in den aktuellen Highlighter gequetscht worden waren. Das Ergebnis dieses Wunsches war eine neue Scorer-Implementierung namens SpanScorer.
Der neue SpanScorer würde den TokenStream in einen schnellen MemoryIndex für ein einzelnes Dokument speichern, die Abfrage in eine SpanQuery-Annäherung konvertieren und getSpans für den MemoryIndex aufrufen, um alle Positionstreffer für das Dokument zu erhalten. Diese Informationen werden dann bei der Auswertung verwendet, um Abfragebegriffe herauszufiltern, die zwar mit Dokumentbegriffen übereinstimmen, sich aber nicht an der richtigen Position befinden. Der SpanScorer unterstützt jetzt fast alle Lucene-Abfragen und ist bei Abfrageklauseln, die nicht positionsabhängig sind, genauso schnell wie der QueryScorer.
Lucene fügte den SpanScorer in Version 2.4 hinzu und auch Solr hat in Version 1.3 Unterstützung für den SpanScorer hinzugefügt. Um die Vorteile des SpanScorer in Lucene zu nutzen, verwenden Sie einfach den SpanScorer und nicht den QueryScorer. Sie können den SpanScorer in Solr aktivieren, indem Sie hl.usePhraseHighlighter=true in Ihrer Anfrage übergeben.
Andere Highlighter-Implementierungen…
In Lucene JIRA gibt es noch eine Reihe weiterer Highlighter-Implementierungen. Die interessantesten Ideen, die Sie darin finden, stammen von den beiden Implementierungen, die voraussetzen, dass Termvektoren für die Dokumente, die Sie hervorheben möchten, gespeichert werden. Wenn Sie diese Anforderung durchsetzen können (was wir mit dem Standard-Highlighter noch nicht tun wollen), können Sie den Ansatz verwenden, nur die Begriffe in der Abfrage zu betrachten, anstatt jeden einzelnen Begriff im Dokument zu untersuchen. Dies kann bei umfangreichen Dokumenten ein großer Gewinn sein. Die Nachteile sind, dass es nicht einfach ist (und meines Wissens auch noch nicht gemacht wurde), eine Hervorhebung auf der Grundlage der Position (Phrase/Span-Abfragen) vorzunehmen, und dass die API für benutzerdefinierte Hooks weniger umfangreich ist. Und natürlich müssen Sie TermVectors speichern, um den Highlighter verwenden zu können.