Auf dieser Seite werden die Funktion SEARCH und der erweiterte Abfragemodus beschrieben, die zum Ausführen von Volltextsuchabfragen 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 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 Suche nach einer Wortgruppe behandelt und ignoriert.
Mit dem Wort „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-Dialekt
Im Dialekt „words_phrase“ werden keine speziellen Operatoren verwendet. Alle Begriffe werden als Wortgruppe behandelt. Das bedeutet, dass die Begriffe nebeneinander und in der angegebenen Reihenfolge stehen müssen.
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“.
Erweiterter Abfragemodus
Spanner bietet zwei Volltextsuchmodi: eine einfache tokenbasierte Suche und einen erweiterten Modus namens enhance_query. Wenn die Funktion aktiviert ist, erweitert enhance_query die Suchanfrage um ähnliche Begriffe und Synonyme, wodurch die Wahrscheinlichkeit steigt, dass relevante Ergebnisse gefunden werden.
Um diese Option zu aktivieren, legen Sie das optionale Argument enhance_query=>true in der Funktion SEARCH fest. Die Suchanfrage hotl cal entspricht beispielsweise dem Album Hotel California.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'hotl cal', enhance_query=>true)
PostgreSQL
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'hotl cal', enhance_query=>true)
Der Modus enhance_query ist eine Option für die Abfragezeit. Die Tokenisierung ist davon nicht betroffen.
Sie können denselben Suchindex mit oder ohne enhance_query verwenden.
Google arbeitet kontinuierlich an der Verbesserung der Algorithmen zur Optimierung von Anfragen. Daher kann eine Abfrage mit enhance_query == true im Laufe der Zeit zu leicht unterschiedlichen Ergebnissen führen.
Wenn der Modus enhance_query aktiviert ist, kann sich die Anzahl der Begriffe erhöhen, nach denen die Funktion SEARCH sucht, was die Latenz leicht erhöhen kann.
Anforderungen an SQL-Abfragen
Es gibt mehrere Bedingungen, die eine SQL-Abfrage erfüllen muss, damit ein Suchindex verwendet werden kann. 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, ydefiniert ist, muss die Abfrage einen Konjunkt in derWHERE-Klausel vonx = <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 OperatorenSEARCHundSEARCH_SUBSTRINGverwiesen 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, der sowohl
AlbumTitle_Tokensals auchAlbumStudio_Tokensindexiert:GoogleSQL
SELECT AlbumId FROM Albums WHERE SEARCH(AlbumTitle_Tokens, @p1) AND SEARCH(AlbumStudio_Tokens, @p2)PostgreSQL
In diesem Beispiel werden die Abfrageparameter
$1und$2verwendet, die an „schnelles Auto“ bzw. „blaue 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 NULL-Werte 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.
Suchindizes 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 Veralteter-Dauer 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 Bedingungen für die Indexierung 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 Abfrageparameter anstelle von String-Literalen zu verwenden, wenn Argumente den Wert eines Abfrageparameters zulassen.
Indexauswahl
In Spanner wird in der Regel der effizienteste Index für eine Abfrage mithilfe von kostenbasierten Modellen ausgewählt. 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. Er gibt Nutzern einen Eindruck davon, was ein Suchergebnis enthält und warum es für ihre Anfrage relevant ist.
In Gmail werden beispielsweise Snippets verwendet, um den Teil einer E‑Mail anzugeben, der der Suchanfrage entspricht:

Es bietet mehrere Vorteile, wenn die Datenbank einen Ausschnitt generiert:
- Komfort: Sie müssen keine Logik implementieren, um Snippets aus einer Suchanfrage zu generieren.
- 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
- Informationen zum Ranking von Suchergebnissen
- Weitere Informationen zum Ausführen einer Teilstring-Suche
- Informationen zum Paginieren von Suchergebnissen
- Volltext- und Nicht-Text-Suchanfragen kombinieren
- Mehrere Spalten durchsuchen