Lösung für Synonyme mit mehreren Begriffen in Lucene/Solr unter Verwendung des Auto Phrasing TokenFilter

In einem früheren Blogbeitrag habe ich den AutoPhrasingTokenFilter vorgestellt. Dieser Filter wurde entwickelt, um Substantiv-Phrasen zu erkennen, die eine einzelne…

In einem früheren Blogbeitrag habe ich den AutoPhrasingTokenFilter vorgestellt. Dieser Filter wurde entwickelt, um Substantiv-Phrasen zu erkennen, die eine einzelne Entität oder „Sache“ darstellen. In diesem Beitrag zeige ich, wie die Verwendung dieses Filters in Kombination mit einem Synonymfilter, der so konfiguriert ist, dass er die Vorteile von AutoPhrasing nutzt, dazu beitragen kann, ein anhaltendes Problem in Lucene/Solr zu lösen – nämlich den Umgang mit Synonymen mit mehreren Begriffen.

Das Problem mit Multi-Term-Synonymen in Lucene/Solr ist gut dokumentiert (siehe Jack Krupanskys Vorschlag, John Berrymans ausgezeichnete Zusammenfassung und Nolan Lawsons Query Parser-Lösung ). Im Grunde genommen handelt es sich um ein Problem mit parallelen Begriffspositionen in der synonym-erweiterten Token-Liste – basierend auf der Art und Weise, wie der Lucene-Indexer den analysierten Token-Strom aufnimmt. Der Indexer achtet zwar auf die Startposition eines Tokens, aber nicht auf das Inkrement der Positionslänge. Dies führt dazu, dass Token mit mehreren Begriffen die nachfolgenden Begriffe im Token-Stream überlappen, anstatt eine streng parallele Beziehung (sowohl in Bezug auf die Start- als auch auf die Endposition) zu ihren synonymen Begriffen zu unterhalten. Statt eines sauberen „Zustandsgraphen“ erhalten wir daher ein Muster, das als „Verwurstung“ bezeichnet wird und die 1:1-Zuordnung von Begriffen zu synonymen Begriffen innerhalb des Textflusses nicht genau wiedergibt (siehe Blogbeitrag von Mike McCandless zu diesem Thema). Dieses Problem verschwindet, wenn alle Synonympaare aus einzelnen Token bestehen.

Das Problem mit den Multi-Term-Synonymen wurde in einem Lucene JIRA-Ticket(LUCENE-1622) beschrieben, das immer noch als „Unresolved“ markiert ist:

  • Wenn Mehrwortsynonyme zusammen mit dem ursprünglichen Tokenstrom (an überlappenden Positionen) indiziert werden, führt eine Abfrage nach einer partiellen Synonymsequenz (z.B. „big“ im Synonym „big apple“ für „new york city“) zu einem Treffer im Dokument;
  • es gibt Probleme mit der Hervorhebung des Originaldokuments, wenn ein Synonym gefunden wird (siehe Unit-Tests für ein Beispiel),
  • Wenn das Synonym eine andere Länge hat als die ursprüngliche Sequenz der abzugleichenden Token, dann werden Phrasenabfragen, die das Synonym und die ursprüngliche Sequenzgrenze umfassen, nicht gefunden. Beispiel: „big apple“ ist ein Synonym für „new york city“. Eine Phrasenabfrage „big apple restaurants“ wird nicht mit „new york city restaurants“ übereinstimmen.

Aus irgendeinem Grund ist das Problem als „geringfügig“ markiert!

Die Lösung scheint darin zu bestehen, die Synonymexpansion nur zum Zeitpunkt der Abfrage zu verwenden, aber auch hier gibt es Probleme mit Phrasenabfragen, falscher Verstärkung seltener Synonyme aufgrund von IDF und Problemen beim Abgleich von Synonymen mit mehreren Begriffen – die dazu neigen, mehr abzugleichen, als sie sollten (siehe oben zitierte Referenzen). Wie wir Suchexperten zu sagen pflegen, hat die Lucene/Solr-Lösung für Synonyme Probleme mit der Präzision und der Wiedererkennung.

Eine Lösung für dieses Problem besteht darin, es ganz zu vermeiden, indem Sie dafür sorgen, dass die Synonymliste nur einzelne Token enthält. Eine vorgeschlagene Möglichkeit, dies zu tun, ist die Verwendung von Einweg-Erweiterungen wie big apple,new york city => nyc sowohl im Index als auch zur Abfragezeit. Dies funktioniert jedoch nicht, da der Abfrageparser nicht über Leerzeichen hinaus „sehen“ kann(LUCENE-2605), so dass eine Suche nach text:big apple in text:big text:apple umgewandelt wird und die erwartete Synonymerweiterung nicht stattfindet. Es funktioniert, wenn Sie nach text: „big apple“ suchen, aber wenn Sie Phrasen zitieren müssen, damit ihre Synonyme funktionieren, wird der Zweck von Synonymen für Phrasen zunichte gemacht. Sie sollten „einfach funktionieren“, wenn ein Benutzer die Phrase in einen Suchstring eingibt.

Von LUCENE-2605 (ebenfalls derzeit ungelöst):

  • Der Queryparser parst die Eingabe auf Leerzeichen und sendet jeden durch Leerzeichen getrennten Begriff an seinen eigenen unabhängigen Token-Stream.
  • Dies führt zu einer Unterbrechung der folgenden Abfragen, da sie nicht über Leerzeichengrenzen hinweg sehen können:
    • n-gram Analyse
    • Gürtelrose
    • Synonyme (insbesondere Mehrwortsynonyme für durch Leerzeichen getrennte Sprachen)
    • Sprachen, in denen ein ‚Wort‘ Leerzeichen enthalten kann (z. B. Vietnamesisch)
  • Es ist auch ziemlich unerwartet, da die Benutzer denken, dass ihre Zeichenfilter / Tokenizer / Tokenfilter bei der Indexierung und bei der Abfrage das Gleiche tun, aber in vielen Fällen können sie das nicht. Stattdessen würde der Queryparser vorzugsweise nur echte ‚Operatoren‘ parsen. (Kursiv- und Fettschrift hinzugefügt)

Zumindest dieses ist als ‚Major‘ gekennzeichnet, aber zum Zeitpunkt der Erstellung dieses Artikels noch nicht gelöst (es wurde 2010 eröffnet).

Daraus ergibt sich, dass die Lösung des Problems darin besteht, Synonyme mit mehreren Begriffen ganz zu vermeiden (wenn möglich), da die zugrundeliegenden Probleme unlösbar – oder zumindest schwer zu fassen – zu sein scheinen. Wenn dies in der Welt der Software geschieht und eine Fehlerbehebung nicht unmittelbar bevorzustehen scheint, suchen wir stattdessen nach einer … Umgehung! 😎 Hier kommt der AutoPhrasingTokenFilter ins Spiel. Er bietet eine Möglichkeit, Mehrwortsätze in einzelne Token umzuwandeln und kann so als Vorläufer für die Synonymzuordnung verwendet werden. Die Lösung hat eine Reihe von Vorteilen – sie bewahrt die Phrasensuche und phrasenübergreifende Suchen wie ‚big apple restaurants‘. Hervorhebungen werden beibehalten und sie funktioniert entweder zur Index- oder zur Abfragezeit (wenn Sie sich Sorgen um das IDF-Problem machen). Und warum? Weil es das eigentliche Problem nicht löst, sondern es einfach vermeidet! Mit anderen Worten: „Wenn Sie sie nicht besiegen können, schließen Sie sich ihnen an“.

Behebung des LUCENE-1622 Problems mit dem Auto Phrasing TokenFilter

Der genaue Anwendungsfall, der in LUCENE-1622 beschrieben wird, kann „behoben“ werden, indem man feststellt, dass die Phrasen „Big Apple“ und „New York City“ eine einzige Einheit darstellen sollen – die große Stadt New York (eine weitere mögliche synonyme Phrase). Wie im vorigen Beitrag beschrieben, kann der AutoPhrasingTokenFilter verwendet werden, um diese Phrasen in einem Token-Stream zu erkennen und sie in einzelne Token umzuwandeln. Um die Zeichenposition beizubehalten, wurde ein neues Attribut hinzugefügt: replaceWhitespaceWith, so dass die Länge des autophrasierten Tokens der ursprünglichen Phrasenlänge entspricht, aber vom Abfrageparser nicht aufgespalten wird – weil es jetzt keine Leerzeichen enthält. Das Ersetzen des Leerzeichens durch ein anderes Zeichen in den indizierten Daten hilft auch bei der Hervorhebung, die von den Zeichenpositionen abhängt. Der Quellcode für diesen Filter ist auf github verfügbar.

Wenn wir also eine autophrases.txt-Datei haben, die aus:

big apple
new york city
city of new york
new york new york
new york ny
ny city
ny ny
new york

Sobald wir den AutophrasingTokenFilter so konfiguriert haben, dass er Leerzeichen durch einen Unterstrich ersetzt (siehe Konfiguration unten), können wir einen synonyms.txt Eintrag wie folgt erstellen:

big_apple,new_york_city,city_of_new_york,new_york_new_york,new_york_ny,ny_city,ny_ny,nyc

(Beachten Sie, dass die Verwendung des Zeichens ‚_‘ die Stemming-Filter unterbricht, so dass Sie wahrscheinlich einen Buchstaben wie ‚x‘ verwenden sollten, aber der Unterstrich wird hier der Klarheit halber verwendet)

Beachten Sie, dass das ‚of‘ in der Phrase ‚City of New York‘ normalerweise als Stoppwort betrachtet wird. Wenn wir jedoch den AutoPhrasing-Filter vor den StopFilter setzen, wird er das Stoppwort „verstecken“, so dass es in der Phrase verwendet werden kann. Dies ist nützlich für Fälle, in denen wir Stoppwörter haben, die in Phrasen enthalten sind, aber ansonsten als Störwörter behandelt werden sollten.

Die Konfiguration des Textanalyzers sieht wie folgt aus. Beachten Sie, dass ich den AutoPhrasingTokenFilter nur im Indexanalysator einsetze (mit includeTokens=true, damit Abfragen mit einzelnen Begriffen und Teilphrasen weiterhin gefunden werden). Die Verwendung von AutoPhrasing im Query Analyzer hat aufgrund von LUCENE-2605 keine Wirkung. Der SynonymFilter befindet sich ebenfalls nur im Index Analyzer. Er kann auch in den Query Analyzer integriert werden, wenn Sie dies wünschen. Dies ist besser, wenn sich Ihre Synonymliste häufig ändert, führt aber zu dem IDF-Problem:

<fieldType name="text_autophrase" class="solr.TextField"
           positionIncrementGap="100">
  <analyzer type="index">
    <tokenizer class="solr.StandardTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory" />
    <filter class="com.lucidworks.analysis.AutoPhrasingTokenFilterFactory"
            phrases="autophrases.txt" includeTokens="true"
            replaceWhitespaceWith="_" />
    <filter class="solr.StopFilterFactory" ignoreCase="true"
            words="stopwords.txt" enablePositionIncrements="true" />
    <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt"
            ignoreCase="true" expand="true" />
    <filter class="solr.KStemFilterFactory" />
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.StandardTokenizerFactory" />
    <filter class="solr.LowerCaseFilterFactory" />
    <filter class="solr.StopFilterFactory" ignoreCase="true"
            words="stopwords.txt" enablePositionIncrements="true" />
    <filter class="solr.KStemFilterFactory" />
  </analyzer>
</fieldType>

Behebung des LUCENE-2605 Problems:

Die Behebung des in LUCENE-2605 identifizierten Problems erfordert ein wenig mehr Arbeit. Da der Query Parser nur einzelne Token an den Query Analyzer sendet, gibt es keine Möglichkeit, diese in der Token-Filterkette des Analyzers zusammenzufügen (auch wenn die Solr Analysis Konsole dies vorschlägt!). Die Lösung besteht darin, die automatische Phrasierung zur Abfragezeit durchzuführen, bevor die Abfrage an den Query Parser gesendet wird. Ein QParserPlugin-Wrapper, der die Abfragesyntax beibehält und die Abfrage automatisch formuliert, bevor er sie an eine „echte“ Abfrageparser-Implementierung weiterleitet, erfüllt diesen Zweck. Mit anderen Worten, es macht etwas Ähnliches wie das, was in LUCENE-2605 vorgeschlagen wurde, indem es „um“ die Abfrageoperatoren herum filtert. Das AutoPhrasingQParserPlugin verwendet intern den AutoPhrasingTokenFilter. Da es sich um einen Abfrageparser handelt, ist eine separate Konfiguration in solrconfig.xml erforderlich:

<requestHandler name="/autophrase" class="solr.SearchHandler">
   <lst name="defaults">
     <str name="echoParams">explicit</str>
     <int name="rows">10</int>
     <str name="df">text</str>
   </lst>
   <lst name="invariants">
     <str name="defType">autophrasingParser</str>
   </lst>
  </requestHandler>

  <queryParser name="autophrasingParser"
               class="com.lucidworks.analysis.AutoPhrasingQParserPlugin" >
    <str name="phrases">autophrases.txt</str>
    <str name=”replaceWhitespaceWith”>_</str>
  </queryParser>

Um den in LUCENE-1622 identifizierten Anwendungsfall zu testen, wurden mehrere Testdokumente erstellt und in einer Solr-Sammlung indiziert (erkennen Sie hier das Thema? New Yorker wie ich sind Chauvinisten 🙂 )

  <doc>
    <field name="id">1001</field>
    <field name="name">Doc 1</field>
    <field name="text">Example from LUCENE-1622 search for New York City restaurants</field>
  </doc>
  <doc>
    <field name="id">1002</field>
    <field name="name">Doc 2</field>
    <field name="text">There are many fine restaurants in the great City of New York.</field>
  </doc>
  <doc>
    <field name="id">1003</field>
    <field name="name">Doc 3</field>
    <field name="text">Multi-term synonyms in Solr is a big problem, and its not a new one.</field>
  </doc>
  <doc>
    <field name="id">1004</field>
    <field name="name">Doc 4</field>
    <field name="text">The empire state, New York State is a big state. There are many things to do in the State of New York.</field>
  </doc>
  <doc>
    <field name="id">1005<field>
    <field name="name">Doc 5</field>
    <field name="text">Many people like to visit the Big Apple, but they wouldn't want to live there.</field>
  </doc>
  <doc>
    <field name="id">1006</field>
    <field name="name">Doc 6</field>
    <field name="text">I like New York, New York its a hell of a town - the West Side's up and the Battery's down!</field>
  </doc>
  <doc>
    <field name="id">1007</field>
    <field name="name">Doc 7</field>
    <field name="text">I have a nice house near New Paltz. New Paltz has some nice restaurants and apple orchards too.</field>
  </doc>
  <doc>
    <field name="id">1008</field>
    <field name="name">Doc 8</field>
    <field name="text">As a New York baseball fan, you can root for the Yankees or you can root for the Mets. You can't root for both.</field>
  </doc>
  <doc>
    <field name="id">1009</field>
    <field name="name">Doc 9</field>
    <field name="text">The capital of New York is Albany.</field>
  </doc>
  <doc>
    <field name="id">1010</field>
    <field name="name">Doc 10</field>
    <field name="text">The Grand Old Duke of York, he had ten thousand men. He marched them up to the top of the hill and he marched them down again.</field>
  </doc>
  <doc>
    <field name="id">1011</field>
    <field name="name">Doc 11</field>
    <field name="text">There are some great parks in NYC, including Central Park and Riverside Park.</field>
  </doc>
  <doc>
    <field name="id">1012</field>
    <field name="name">Doc 12</field>
    <field name="text">It would be nice to live at 123 Broadway, NY, NY 10013.</field>
  </doc>
</add>

Abfrage-Tests: Vergleich des OOB-Verhaltens mit Auto Phrasing:

Da die Stadt New York in einem gleichnamigen Bundesstaat liegt, sind Abfragen nach ‚New York‘ mehrdeutig und sollten beide Begriffe zurückgeben. Solr gibt auch Dokumente zurück, die nur die Begriffe ’new‘ und ‚york‘ enthalten (‚/select?q=New+York‘). Betrachten Sie also die beiden Dokumente über den ‚Grand Old Duke of York‘ und ‚Multibegriffssynonyme in Solr‘, die in der folgenden Ergebnismenge zurückgegeben werden. Sie werden gefunden, weil sie die Begriffe ’new‘ und ‚york‘ enthalten, aber nicht wirklich relevant für die wahrscheinliche Absicht der Abfrage sind. Außerdem gibt es Dokumente über New York, die nicht gefunden werden, weil sie Synonyme für New York City verwenden. In diesem Fall leidet der OOTB SearchHandler also sowohl unter Präzisions- als auch unter Rückruffehlern.

"response": {
  "numFound": 9,
  "start": 0,
  "docs": [
    {
      "id": "1009",
      "text": "The capital of New York is Albany."
    },
    {
      "id": "1006",
      "text": "I like New York, New York its a hell of a town - the West Side's up and the Battery's down!"
    },
    {
      "id": "1002",
      "text": "There are many fine restaurants in the great City of New York."
    },
    {
      "id": "1004",
      "text": "The empire state, New York State is a big state. There are many things to do in the State of New York."
    },
    {
      "id": "1001",
      "text": "Example from LUCENE-1622 search for New York City restaurants"
    },
    {
      "id": "1008",
      "text": "As a New York baseball fan, you can root for the Yankees or you can root for the Mets. You can't root for both."
    },
    {
      "id": "1010",
      "text": "The Grand Old Duke of York, he had ten thousand men."
    },
    {
      "id": "1007",
      "text": "I have a nice house near New Paltz. New Paltz has some nice restaurants and apple orchards too."
    },
    {
      "id": "1003",
      "text": "Multi-term synonyms in Solr is a big problem, and its not a new one."
    }
  ]
}

Mit dem Filter für die automatische Phrasierung gibt die Suche nach New York (/autophrase?q=New+York) nur Dokumente zurück, die diese Phrase enthalten (d.h. die sowohl in New York City als auch im Staat New York enthalten sind) und schließt Datensätze aus, die Synonyme wie NYC oder Big Apple enthalten:

"response": {
    "numFound": 6,
    "start": 0,
    "docs": [
      {
        "id": "1009",
        "name": "Doc 9",
        "text": "The capital of New York is Albany.",
        "_version_": 1473362972290056200
      },
      {
        "id": "1002",
        "name": "Doc 2",
        "text": " The are many fine restaurants in the great City of New York.",
        "_version_": 1473362972282716200
      },
      {
        "id": "1004",
        "name": "Doc 4",
        "text": "The empire state, New York State is a big state. There are many things to do in the State of New York.",
        "_version_": 1473362972284813300
      },
      {
        "id": "1001",
        "name": "Doc 1",
        "text": "Example from LUCENE-1622 search for New York City restaurants",
        "_version_": 1473362972255453200
      },
      {
        "id": "1006",
        "name": "Doc 6",
        "text": "I like New York, New York its a hell of a town - the West Side's up and the Battery's down!",
        "_version_": 1473362972285862000
      },
      {
        "id": "1008",
        "name": "Doc 8",
        "text": "As a New York baseball fan, you can root for the Yankees or you can root for the Mets. You can't root for both.",
        "_version_": 1473362972289007600
      }
    ]
  }

Und die Suche nach New York City (/autophrase?q=new+york+city) oder einem seiner Synonyme ( big apple, city of new york, nyc, etc.) gibt nur Datensätze zurück, die Datensätze über die Stadt New York enthalten. Beachten Sie, dass Datensätze über den Staat New York oder die Baseballteams korrekt ausgeschlossen werden:

"response": {
  "numFound": 6,
  "start": 0,
  "docs": [
    {
      "id": "1002",
      "text": "There are many fine restaurants in the great City of New York."
    },
    {
      "id": "1001",
      "text": "Example from LUCENE-1622 search for New York City restaurants"
    },
    {
      "id": "1005",
      "text": "Many people like to visit the Big Apple, but they wouldn't want to live there."
    },
    {
      "id": "1006",
      "text": "I like New York, New York its a hell of a town - the West Side's up and the Battery's down!"
    },
    {
      "id": "1011",
      "text": "There are some great parks in NYC, including Central Park and Riverside Park."
    },
    {
      "id": "1012",
      "text": "It would be nice to live at 123 W Broadway, NY, NY 10013. "
    }
  ]
}

Um auf den ursprünglichen Anwendungsfall in LUCENE-1622 zurückzukommen: Die boolesche Suche nach einem Synonym von NYC AND restaurants, wie z.B. big apple AND restaurants (oder +big apple +restaurants), liefert nur Datensätze über die Restaurantszene in New York City:

"response": {
  "numFound": 2,
  "start": 0,
  "docs": [
    {
      "id": "1002",
      "text": "There are many fine restaurants in the great City of New York."
    },
    {
      "id": "1001",
      "text": "Example from LUCENE-1622 search for New York City restaurants"
    }
  ]
}

Fazit

Der AutoPhrasingTokenFilter kann ein wichtiges Werkzeug sein, um eines der schwierigeren Probleme bei der Lucene/Solr-Suche zu lösen – den Umgang mit Synonymen mit mehreren Begriffen. Gleichzeitig können wir ein anderes schwerwiegendes Problem aller Suchmaschinen verbessern – die Konzentration auf einzelne Token und die Mehrdeutigkeiten, die auf dieser Ebene vorhanden sind. Indem wir den Schwerpunkt stärker auf Phrasen verlagern, die als semantische Einheiten oder Spracheinheiten (z.B. „Dinge“) behandelt werden sollten, ist die Suchmaschine besser in der Lage, Ergebnisse zu liefern, die auf dem basieren, wonach der Benutzer sucht, und nicht auf Dokumenten, die Wörter enthalten, die der Anfrage entsprechen. Wir bewegen uns von der Suche mit einem „Sack voller Wörter“ zur Suche mit einem „Sack voller Dinge“.

You Might Also Like

Vom Suchunternehmen zum praktischen KI-Pionier: Unsere Vision für 2025 und darüber hinaus

CEO Mike Sinoway gibt Einblicke in die Zukunft der KI und stellt...

Read More

Wenn KI schief geht: Fehlschläge in der realen Welt und wie man sie vermeidet

Lassen Sie nicht zu, dass Ihr KI-Chatbot einen 50.000 Dollar teuren Tahoe...

Read More

Lucidworks Kernpakete: Branchenoptimierte KI-Such- und Personalisierungslösungen

Entdecken Sie unsere umfassenden Core Packages, die Analytics Studio, Commerce Studio und...

Read More

Quick Links