Abfrageübersicht

Auf dieser Seite werden die Funktion SEARCH und ihre verschiedenen erweiterten Funktionen beschrieben, die zum Ausführen von Volltextsuchanfragen für Spanner-Tabellen verwendet werden.

Suchindex abfragen

Spanner bietet die Funktion SEARCH für Suchindexabfragen. Ein Beispiel hierfür wäre eine Anwendung, in der Nutzer Text in ein Suchfeld eingeben und die Anwendung die Nutzereingabe direkt an die SEARCH-Funktion sendet. Die Funktion SEARCH würde dann einen Suchindex verwenden, um diesen Text zu finden.

Für die Funktion SEARCH sind zwei Argumente erforderlich:

  • Name des Suchindex
  • Eine Suchanfrage

Die Funktion SEARCH funktioniert nur, wenn ein Suchindex definiert ist. Die Funktion SEARCH kann mit beliebigen SQL-Konstrukten wie Filtern, Aggregationen oder Joins kombiniert werden.

Die Funktion SEARCH kann nicht mit Transaktionsabfragen verwendet werden.

In der folgenden Abfrage wird die Funktion SEARCH verwendet, um alle Alben zurückzugeben, deren Titel entweder friday oder monday enthält:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')

PostgreSQL

In diesem Beispiel wird spanner.search verwendet.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'friday OR monday')

Suchanfrage

Für Suchanfragen wird standardmäßig die Syntax für Rohsuchanfragen verwendet. Mit dem Argument SEARCH dialect können alternative Syntaxen angegeben werden.

rquery-Dialekt

Der Standarddialekt ist raw search query (Rohsuchanfrage). Spanner verwendet eine domainspezifische Sprache (Domain-specific Language, DSL) namens rquery.

Die rquery-Sprache folgt denselben Regeln wie der Plain-Text-Tokenizer, wenn die eingegebene Suchanfrage in einzelne Begriffe unterteilt wird. Dazu gehört auch die Segmentierung asiatischer Sprachen.

Informationen zur Verwendung von rquery finden Sie unter rquery-Syntax.

Wörter – Dialekt

Das Wort „dialect“ ähnelt „rquery“, ist aber einfacher. Es werden keine speziellen Operatoren verwendet. OR wird beispielsweise als Suchbegriff und nicht als Disjunktionsoperator behandelt. Die doppelten Anführungszeichen werden als Satzzeichen und nicht als Phrasensuche behandelt und ignoriert.

Bei Verwendung des Wortes „Dialekt“ wird AND implizit auf alle Begriffe angewendet und ist für den Abgleich erforderlich. Beim Aufteilen der eingegebenen Suchanfrage in Begriffe gelten dieselben Regeln wie für den Plaintext-Tokenizer.

Informationen zur Verwendung des Wortes „dialect“ finden Sie unter words-Syntax.

words_phrase dialect

Im Dialekt „words_phrase“ werden keine speziellen Operatoren verwendet. Alle Begriffe werden als Wortgruppe behandelt, d. h., die Begriffe müssen nebeneinander und in der angegebenen Reihenfolge stehen.

Wie bei rquery folgt der Dialekt „words_phrase“ denselben Regeln wie der Plaintext-Tokenizer beim Aufteilen der eingegebenen Suchanfrage in Begriffe.

Informationen zur Verwendung des Dialekts „words_phrase“ finden Sie unter Syntax für „words_phrase“.

Suchanfragen erweitern, um mehr relevante Ergebnisse zu erhalten

Mit den erweiterten Funktionen von Spanner können Sie die Wahrscheinlichkeit erhöhen, relevante Ergebnisse zu finden, da Suchanfragen mit verwandten Begriffen, Synonymen und Rechtschreibkorrekturen erweitert werden. Dazu gehören:

Weitere Informationen finden Sie unter Suche mit Abfrageoptimierung.

Anforderungen an SQL-Abfrage

Damit ein Suchindex verwendet werden kann, muss eine SQL-Abfrage mehrere Bedingungen erfüllen. Wenn diese Bedingungen nicht erfüllt sind, wird entweder ein alternativer Abfrageplan verwendet oder die Abfrage schlägt fehl, wenn kein alternativer Plan vorhanden ist.

Abfragen müssen die folgenden Bedingungen erfüllen:

  • Für die SEARCH-Funktion und die SEARCH_SUBSTRING-Funktionen ist ein Suchindex erforderlich. Spanner unterstützt diese Funktionen nicht in Abfragen für die Basistabelle oder sekundäre Indexe.

  • Für partitionierte Indexe müssen alle Partitionierungsspalten durch eine Gleichheitsbedingung in der WHERE-Klausel der Abfrage gebunden sein.

    Wenn ein Suchindex beispielsweise als PARTITION BY x, y definiert ist, muss die Abfrage einen Konjunkt in der WHERE-Klausel von x = <parameter or constant> AND y = <parameter or constant> haben. Dieser Suchindex wird vom Abfrageoptimierer nicht berücksichtigt, wenn eine solche Bedingung fehlt.

  • Alle TOKENLIST-Spalten, auf die von den Operatoren SEARCH und SEARCH_SUBSTRING verwiesen wird, müssen im selben Suchindex indexiert werden.

    Betrachten Sie beispielsweise die folgende Tabelle und Indexdefinition:

    GoogleSQL

    CREATE TABLE Albums (
        AlbumId STRING(MAX) NOT NULL,
        AlbumTitle STRING(MAX),
        AlbumStudio STRING(MAX),
        AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
        AlbumStudio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumStudio)) HIDDEN
    ) PRIMARY KEY(AlbumId);
    
    CREATE SEARCH INDEX AlbumsTitleIndex ON Albums(AlbumTitle_Tokens);
    CREATE SEARCH INDEX AlbumsStudioIndex ON Albums(AlbumStudio_Tokens);
    

    PostgreSQL

    CREATE TABLE albums (
        albumid character varying NOT NULL,
        albumtitle character varying,
        albumstudio character varying,
        albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
        albumstudio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumstudio)) VIRTUAL HIDDEN,
    PRIMARY KEY(albumid));
    
    CREATE SEARCH INDEX albumstitleindex ON albums(albumtitle_tokens);
    CREATE SEARCH INDEX albumsstudioindex ON albums(albumstudio_tokens);
    

    Die folgende Abfrage schlägt fehl, da es keinen einzelnen Suchindex gibt, in dem sowohl AlbumTitle_Tokens als auch AlbumStudio_Tokens indexiert werden:

    GoogleSQL

    SELECT AlbumId
    FROM Albums
    WHERE SEARCH(AlbumTitle_Tokens, @p1)
        AND SEARCH(AlbumStudio_Tokens, @p2)
    

    PostgreSQL

    In diesem Beispiel werden die Abfrageparameter $1 und $2 verwendet, die an „fast car“ bzw. „blue note“ gebunden sind.

    SELECT albumid
    FROM albums
    WHERE spanner.search(albumtitle_tokens, $1)
        AND spanner.search(albumstudio_tokens, $2)
    
  • Wenn die Spalte für die Sortierreihenfolge Nullwerte zulässt, müssen sowohl das Schema als auch die Abfrage Zeilen ausschließen, in denen die Spalte für die Sortierreihenfolge NULL ist. Weitere Informationen finden Sie unter Sortierreihenfolge des Suchindex.

  • Wenn der Suchindex NULL-gefiltert ist, muss die Abfrage denselben NULL-Filterausdruck enthalten, der in einem Index verwendet wird. Weitere Informationen finden Sie unter NULL-gefilterte Suchindexe.

  • Suchindexe und Suchfunktionen werden in DML, partitionierter DML oder partitionierten Abfragen nicht unterstützt.

  • Suchindexe und Suchfunktionen werden in der Regel in schreibgeschützten Transaktionen verwendet. Wenn die Anwendungsanforderungen veraltete Ergebnisse zulassen, können Sie die Latenz möglicherweise verbessern, indem Sie Suchanfragen mit einer Veraltungsdauer von 10 Sekunden oder länger ausführen. Weitere Informationen finden Sie unter Veraltete Daten lesen. Das ist besonders nützlich für Suchanfragen, die sich auf viele Index-Splits verteilen.

Suchindexe und Suchfunktionen werden in Lese-/Schreibtransaktionen nicht empfohlen. Während der Ausführung sperren Suchanfragen eine gesamte Indexpartition. Eine hohe Anzahl von Suchanfragen in Lese-/Schreibtransaktionen kann daher zu Sperrkonflikten führen, die Latenzspitzen verursachen. Standardmäßig werden Suchindexe in Lese-/Schreibtransaktionen nicht automatisch ausgewählt. Wenn eine Abfrage gezwungen wird, einen Suchindex in einer Lese-/Schreibtransaktion zu verwenden, schlägt sie standardmäßig fehl. Die Anfrage schlägt auch fehl, wenn sie eine der Suchfunktionen enthält. Dieses Verhalten kann mit dem GoogleSQL-Hinweis auf Anweisungsebene @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} überschrieben werden. Abfragen sind jedoch weiterhin anfällig für Sperrkonflikte.

Sobald die Indexvoraussetzungen erfüllt sind, versucht die Abfrageoptimierung, Bedingungen für Nicht-Text-Abfragen (z. B. Rating > 4) zu beschleunigen. Wenn der Suchindex die entsprechende TOKENLIST-Spalte nicht enthält, wird die Bedingung nicht beschleunigt und bleibt eine Restbedingung.

Suchparameter

Suchanfrageargumente werden entweder als Literal oder als Abfrageparameter angegeben. Wir empfehlen, für die Volltextsuche Suchparameter anstelle von Stringliteralen zu verwenden, wenn Argumente den Parameterwert zulassen.

Indexauswahl

In der Regel wählt Spanner den effizientesten Index für eine Abfrage mithilfe von kostenbasierten Modellen aus. Der Hinweis FORCE_INDEX weist Spanner jedoch explizit an, einen bestimmten Suchindex zu verwenden. Das folgende Beispiel zeigt, wie Sie Spanner zwingen, den AlbumsIndex zu verwenden:

GoogleSQL

SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")

PostgreSQL

SELECT albumid
FROM albums/*@force_index=albumsindex*/
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')

Wenn der angegebene Suchindex nicht infrage kommt, schlägt die Anfrage fehl, auch wenn es andere infrage kommende Suchindexe gibt.

Snippets in Suchergebnissen

Ein Snippet ist ein Textausschnitt, der aus einem bestimmten String extrahiert wird und Nutzern einen Eindruck davon vermittelt, was ein Suchergebnis enthält und warum es für ihre Suchanfrage relevant ist.

In Gmail werden beispielsweise Snippets verwendet, um den Teil einer E‑Mail anzugeben, der der Suchanfrage entspricht:

Liste der Snippets

Es bietet mehrere Vorteile, wenn die Datenbank einen Ausschnitt generiert:

  1. Komfort: Sie müssen keine Logik implementieren, um Snippets aus einer Suchanfrage zu generieren.
  2. Effizienz: Durch Snippets wird die Ausgabegröße des Servers reduziert.

Mit der Funktion SNIPPET wird das Snippet erstellt. Sie gibt den relevanten Teil des ursprünglichen Stringwerts zusammen mit den Positionen der hervorzuhebenden Zeichen zurück. Der Client kann dann auswählen, wie das Snippet dem Endnutzer präsentiert wird (z. B. durch Hervorhebung oder Fettdruck).

Im folgenden Beispiel wird SNIPPET verwendet, um Text aus AlbumTitle abzurufen:

GoogleSQL

SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")

PostgreSQL

In diesem Beispiel wird spanner.snippet verwendet.

SELECT albumid, spanner.snippet(albumtitle, 'Fast Car')
FROM albums
WHERE spanner.search(albumtitle_tokens, 'Fast Car')

Nächste Schritte