Auf dieser Seite wird beschrieben, wie Sie TOKENLISTs entweder in einem Suchindex beim Einrichten des Schemas oder in einer Suchanfrage bei der Volltextsuche in Spanner verketten.
TOKENLISTs in einem Suchindex kombinieren
Manchmal muss Ihre Anwendung in einzelnen Feldern suchen. In anderen Fällen muss die Anwendung alle Felder durchsuchen. In einer Tabelle mit zwei Stringspalten soll Ihre Anwendung beispielsweise in beiden Spalten suchen, ohne zu unterscheiden, aus welcher Spalte die Übereinstimmungen stammen.
In Spanner gibt es zwei Möglichkeiten, dies zu erreichen:
- Wörter separat tokenisieren und die resultierenden
TOKENLISTs verketten (empfohlen): - Strings verketten und das Ergebnis tokenisieren:
Beim zweiten Ansatz gibt es zwei Probleme:
- Wenn Sie
TitleoderStudioeinzeln indexieren möchten, zusätzlich zur Indexierung in einem kombiniertenTOKENLIST, wird derselbe Text zweimal in Tokens zerlegt. Dadurch werden für Transaktionen mehr Ressourcen benötigt. - Eine Suche nach einer Wortgruppe umfasst beide Felder. Wenn
@pbeispielsweise auf"Blue Note"festgelegt ist, wird eine Zeile gefunden, die sowohlTitle="Big Blue Note" als auchStudio="Blue Note Studios" enthält.
Beim ersten Ansatz werden diese Probleme behoben, da eine Wortgruppe nur einem Feld entspricht und jedes Stringfeld nur einmal tokenisiert wird, wenn sowohl die einzelnen als auch die kombinierten TOKENLISTs indexiert werden. Obwohl jedes Stringfeld nur einmal tokenisiert wird, werden die resultierenden TOKENLISTs separat im Index gespeichert.
Wörter separat tokenisieren und TOKENLISTs verketten
Im folgenden Beispiel wird jedes Wort tokenisiert und TOKENLIST_CONCAT verwendet, um die TOKENLIST-Werte zu verketten:
GoogleSQL
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
Title STRING(MAX),
Studio STRING(MAX),
Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
Combined_Tokens TOKENLIST AS (TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens])) HIDDEN,
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);
SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);
PostgreSQL
PostgreSQL verwendet
spanner.tokenlist_concat für die Verkettung. Der Abfrageparameter $1 ist an „Hatel Kaliphorn“ gebunden.
CREATE TABLE albums (
albumid character varying NOT NULL,
title character varying,
studio character varying,
title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenlist_concat(ARRAY[spanner.tokenize_fulltext(title), spanner.tokenize_fulltext(studio)])) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);
SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);
Beachten Sie, dass tokenlist_concat nicht title_tokens oder studio_tokens aufruft, sondern stattdessen spanner.tokenize_fulltext(title) und spanner.tokenize_fulltext(studio). Das liegt daran, dass PostgreSQL keine Referenzierung von generierten Spalten in anderen generierten Spalten unterstützt. spanner.tokenlist_concat muss Tokenize-Funktionen aufrufen und darf nicht direkt auf Tokenlist-Spalten verweisen.
Die TOKENLIST-Verkettung kann auch vollständig auf der Abfrageseite implementiert werden.
Weitere Informationen finden Sie unter TOKENLIST-Verkettung auf Abfrageseite.
TOKENLIST_CONCAT wird sowohl für Volltext- als auch für Teilstring-Suchen unterstützt.
In Spanner können Sie Tokenisierungstypen wie TOKENIZE_FULLTEXT und TOKENIZE_SUBSTRING nicht im selben TOKENLIST_CONCAT-Aufruf mischen.
In GoogleSQL kann die Definition von TOKENLIST-Spalten in nicht gespeicherten Spalten geändert werden, um zusätzliche Spalten hinzuzufügen. Das ist nützlich, wenn Sie TOKENLIST_CONCAT eine zusätzliche Spalte hinzufügen möchten. Wenn Sie den Ausdruck einer generierten Spalte ändern, werden vorhandene Zeilen im Index nicht neu gefüllt.
Strings verketten und das Ergebnis tokenisieren
Im folgenden Beispiel werden Strings verkettet und das Ergebnis wird tokenisiert:
GoogleSQL
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
Title STRING(MAX),
Studio STRING(MAX),
Combined_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title || " " || Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);
SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);
PostgreSQL
CREATE TABLE albums (
albumid character varying NOT NULL,
title character varying,
studio character varying,
combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title || ' ' || studio)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);
SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);
TOKENLIST-Verkettung auf Abfrageseite
Der Nachteil bei der Indexierung des verketteten TOKENLIST besteht darin, dass die Speicher- und Schreibkosten steigen. Jedes Token wird jetzt zweimal auf der Festplatte gespeichert: einmal in einer Posting-Liste des ursprünglichen TOKENLIST und einmal in einer Posting-Liste des kombinierten TOKENLIST. Durch die Verkettung von TOKENLIST-Spalten auf der Abfrageseite werden diese Kosten vermieden, aber für die Abfrage werden mehr Rechenressourcen benötigt.
Wenn Sie mehrere TOKENLIST-Elemente verketten möchten, verwenden Sie die Funktion TOKENLIST_CONCAT in der SEARCH-Abfrage. In diesem Abschnitt wird das folgende Beispielschema verwendet:
GoogleSQL
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
Title STRING(MAX),
Studio STRING(MAX),
Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex ON Albums(Title_Tokens, Studio_Tokens);
PostgreSQL
CREATE TABLE albums (
albumid character varying NOT NULL,
title character varying,
studio character varying,
title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex ON albums(title_tokens, studio_tokens);
Mit der folgenden Abfrage wird nach Zeilen gesucht, die die Tokens „blue“ und „note“ an beliebiger Stelle in den Spalten Title und Studio enthalten. Das umfasst Zeilen mit „blue“ und „note“ in der Spalte Title, „blue“ und „note“ in der Spalte Studio sowie „blue“ in der Spalte Title und „note“ in der Spalte Studio oder umgekehrt.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([AlbumTitle_Tokens, Studio_Tokens]), 'blue note')
PostgreSQL
In diesem Beispiel wird spanner.search mit spanner.tokenlist_concat verwendet.
SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[albumtitle_tokens, studio_tokens]), 'blue note')
Die TOKENLIST-Verkettung auf der Schreib- und Abfrageseite führt zu identischen Ergebnissen.
Die Wahl zwischen den beiden ist ein Kompromiss zwischen Festplatten- und Abfragekosten.
Alternativ kann eine Anwendung mehrere TOKENLIST-Spalten durchsuchen und OR zusammen mit der Funktion SEARCH verwenden:
GoogleSQL
SEARCH(AlbumTitle_Tokens, 'Blue Note') OR SEARCH(Studio_Tokens, 'Blue Note')
PostgreSQL
spanner.search(albumtitle_tokens, 'Blue Note') OR spanner.search(studio_tokens, 'Blue Note')
Dies hat jedoch eine andere Semantik. Sie entspricht nicht Alben, bei denen AlbumTitle_Tokens „blue“, aber nicht „note“ enthält und Studio_Tokens „note“, aber nicht „blue“ enthält.
Nächste Schritte
- Weitere Informationen zu Volltextsuchanfragen
- Weitere Informationen zu Suchindexen