Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann die boolesche Volltextsuche in MySQL optimiert werden? (Oder womit soll es ersetzt werden?) - C#

Zunächst sollten Sie erkennen, dass die RDBMS-Unterstützung für die Volltextindizierung ein Hack ist, um eine Technologie zu erzwingen, die einen effizienten Zugriff auf strukturierte Daten ermöglicht, um mit unstrukturiertem Text umzugehen. (Ja, das ist nur mein Meinung. Bei Bedarf kann ich es verteidigen, da ich beide Technologien sehr gut verstehe.;)

Was kann also getan werden, um die Suchleistung zu verbessern?

Option Eins – „Das beste Tool für die Aufgabe“

Der beste Weg, um die Volltextsuche innerhalb eines Korpus von Dokumenten zu handhaben, ist die speziell dafür entwickelte Technologie, wie z. B. SOLR (Lucene) von Apache oder Sphinx von äh, Sphinx.

Aus Gründen, die weiter unten deutlich werden, empfehle ich diesen Ansatz dringend.

Option 2 – Laden Sie Ihre Ergebnisse vorab

Beim Erstellen textbasierter Suchlösungen besteht der übliche Ansatz darin, alle Dokumente in einem einzigen durchsuchbaren Index zu indizieren, und obwohl dies der zweckmäßigste Ansatz sein mag, ist es nicht der einzige Ansatz.

Angenommen, das, wonach Sie suchen, lässt sich leicht anhand einer Reihe bekannter Regeln quantifizieren, könnten Sie eher einen „geführten“ Suchstil anbieten als nur einen unqualifizierten Volltext. Was ich damit meine ist, wenn Ihre Anwendung davon profitieren könnte, Benutzer zu Ergebnissen zu leiten, können Sie verschiedene Ergebnissätze basierend auf einem bekannten Satz von Regeln in ihre eigenen Tabellen vorab laden und so die Masse der zu durchsuchenden Daten reduzieren.

Wenn Sie davon ausgehen, dass die Mehrheit Ihrer Benutzer von einem bekannten Satz von Suchbegriffen in einer bekannten Reihenfolge profitieren wird, können Sie Ihre Such-Benutzeroberfläche so konstruieren, dass diese Begriffe bevorzugt werden.

Angenommen, die Mehrheit der Benutzer sucht nach einer Vielzahl von Automobilen, könnten Sie vordefinierte Suchen basierend auf Modell, Jahr, Zustand usw. anbieten. Ihre Such-Benutzeroberfläche würde als eine Reihe von Dropdown-Menüs gestaltet, um Benutzer zu bestimmten Ergebnissen zu führen.

Oder wenn die Mehrheit der Suchen nach einem bestimmten Hauptthema erfolgt (z. B. „Automobile“), können Sie eine Tabelle mit nur den Datensätzen vordefinieren, die Sie zuvor als mit Automobilen in Verbindung stehend identifiziert haben.

Beide Ansätze würden die Anzahl der zu durchsuchenden Datensätze verringern und somit die Antwortzeiten verlängern.

Option 3 – „Roll Your Own“

Wenn Sie keine externe Suchtechnologie in Ihr Projekt integrieren können und das Vorabladen keine Option ist, gibt es immer noch Möglichkeiten, die Antwortzeiten für Suchanfragen erheblich zu verbessern, aber sie unterscheiden sich je nachdem, was Sie erreichen müssen und wie die Suche ausgeführt werden soll .

Wenn Sie erwarten, dass Benutzer nach einzelnen Schlüsselwörtern oder Phrasen und booleschen Beziehungen zwischen ihnen suchen, sollten Sie erwägen, Ihren eigenen 'umgekehrter Index ' Ihres Korpus. (Dies tut bereits die boolesche Volltextsuche von MySQL, aber wenn Sie es selbst tun, können Sie sowohl die Geschwindigkeit als auch die Genauigkeit der Suche besser steuern.)

So erstellen Sie einen invertierten Index aus Ihren vorhandenen Daten:

Schritt 1. Erstellen Sie drei Tabellen

    // dict - a dictionary containing one row per unique word in corpus  
    create table dict (    
      id int primary key,  
      word varchar  
    )

    // invert - an inverted_index to map words to records in corpus  
    create table invert (    
      id int primary key,  
      rec_id int,  
      word_id int  
    )

    // stopwords - to contain words to ignore when indexing (like a, an, the, etc)
    create table stopwords ( 
      id int primary key,  
      word varchar  
    )

Hinweis:Dies ist nur eine Skizze. Sie werden Indizes und Beschränkungen usw. hinzufügen wollen, wenn Sie diese Tabellen tatsächlich erstellen.

Die Stoppworttabelle wird verwendet, um die Größe Ihres Index auf nur die Wörter zu reduzieren, die für die erwarteten Abfragen der Benutzer von Bedeutung sind. Zum Beispiel ist es selten sinnvoll, englische Artikel wie „a“, „an“, „the“ zu indizieren, da sie keinen sinnvollen Beitrag zur Stichwortsuche leisten.

In der Regel benötigen Sie eine speziell erstellte Stoppwortliste an die Bedürfnisse Ihrer Anwendung. Wenn Sie niemals erwarten, dass Nutzer die Begriffe „rot“, „weiß“ oder „blau“ in ihre Suchanfragen aufnehmen, oder wenn diese Begriffe in allen vorkommen durchsuchbaren Datensatz, möchten Sie sie Ihrer Stoppwortliste hinzufügen.

Siehe den Hinweis am Ende dieser Nachricht für Anweisungen zur Verwendung Ihrer eigenen Stoppwortliste in MySQL.

Siehe auch:

Schritt 2. Erstellen Sie den invertierten Index

Um einen invertierten Index aus Ihren vorhandenen Datensätzen zu erstellen, müssen Sie (Pseudo-Code):

    foreach( word(w) in record(r) ) {
      if(w is not in stopwords) {
        if( w does not exist in dictionary) {
          insert w to dictionary at w.id
        }
        insert (r.id, w.id) into inverted_index
      }
    }
Mehr zu Stoppwörtern:

Anstatt eine bestimmte Stoppwortliste zu verwenden, könnte der Test „if(w is not in stopwords)“ andere Entscheidungen treffen, entweder anstelle oder als Ergänzung zu Ihrer Liste inakzeptabler Wörter.

Ihre Anwendung möchte möglicherweise alle Wörter mit weniger als 4 Zeichen herausfiltern oder nur einschließen Wörter aus einem vordefinierten Satz.

Indem Sie Ihren eigenen invertierten Index erstellen, erhalten Sie eine viel größere und präzisere Kontrolle über die Suche.

Schritt 3. Den invertierten Index mit SQL abfragen

Dieser Schritt hängt wirklich davon ab, wie Sie erwarten, dass Abfragen an Ihren Index gesendet werden.

Wenn Abfragen "fest codiert" werden sollen, können Sie die Select-Anweisung einfach selbst erstellen, oder wenn Sie vom Benutzer eingegebene Abfragen unterstützen müssen, müssen Sie die von Ihnen gewählte Abfragesprache in eine SQL-Anweisung konvertieren (normalerweise mit einer einfacher Parser).

Angenommen, Sie möchten alle Dokumente abrufen, die der logischen Abfrage „(Wort1 UND Wort2) ODER Wort3“ entsprechen, könnte ein möglicher Ansatz sein:

CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS 
    ( SELECT rec_id, COUNT(rec_id) AS count 
      FROM invert AS I, dict AS D 
      WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2') 
      GROUP BY I.rec_id 
      HAVING count=2
    ) 
    UNION (
      SELECT rec_id, 1 AS count 
      FROM invert AS I, dict AS D
      WHERE I.word_id=D.id AND D.word='word3'
    );

SELECT DISTINCT rec_id FROM temp_results;

DROP TABLE temp_results;

HINWEIS:Dies ist nur ein erster Pass von der Oberseite meines Kopfes. Ich bin zuversichtlich, dass es effizientere Möglichkeiten gibt, einen booleschen Abfrageausdruck in eine effiziente SQL-Anweisung umzuwandeln, und begrüße alle Verbesserungsvorschläge.

Um nach Phrasen zu suchen, müssen Sie dem invertierten Index ein Feld hinzufügen, um die Position darzustellen, an der das Wort in seinem Datensatz vorkam, und dies in Ihre SELECT einbeziehen.

Und schließlich müssen Sie Ihren invertierten Index aktualisieren, wenn Sie neue Datensätze hinzufügen oder alte löschen.

Schlusswort

"Volltextsuche" fällt unter einen sehr großen Forschungsbereich, der als "Information Retrieval" oder IR bekannt ist, und es gibt viele Bücher zu diesem Thema, darunter

Weitere Informationen finden Sie bei Amazon.

Notizen

So verwenden Sie Ihre eigene Liste von Stoppwörtern in MySQL

So verwenden Sie Ihre eigene Stoppwortliste in MySQL:

  1. Erstellen Sie Ihre eigene Liste mit Stoppwörtern, ein Wort pro Zeile, und speichern Sie sie an einem bekannten Ort auf Ihrem Server, sagen wir:/usr/local/lib/IR/stopwords.txt

  2. Bearbeiten Sie my.cnf, um die folgenden Zeilen hinzuzufügen oder zu aktualisieren:
        [mysqld]  
        ft_min_word_len=1    
        ft_max_word_len=40  
        ft_stopword_file=/usr/local/lib/IR/stopwords.txt
    

    Dadurch wird die minimale und maximale Länge zulässiger Wörter auf 1 bzw. 40 festgelegt und mysqld mitgeteilt, wo Ihre benutzerdefinierte Liste von Stoppwörtern zu finden ist.

    (Anmerkung:Der Standardwert für ft_max_word_len ist 84, was meiner Meinung nach ziemlich übertrieben ist und dazu führen kann, dass Reihen von Zeichenfolgen indiziert werden, die keine echten Wörter sind.)

  3. Starten Sie mysqld neu

  4. Alle volltextbezogenen Indizes löschen und neu erstellen