Auf dieser Seite wird beschrieben, wie Sie Suchindexe hinzufügen. Die Volltextsuche wird auf Einträge im Suchindex angewendet.
Suchindexe verwenden
Sie können einen Suchindex für alle Spalten erstellen, die für Volltextsuchen verfügbar sein sollen. Verwenden Sie zum Erstellen eines Suchindex die DDL-Anweisung CREATE SEARCH INDEX
. Verwenden Sie die DDL-Anweisung ALTER SEARCH INDEX
, um einen Index zu aktualisieren. Spanner erstellt und verwaltet den Suchindex automatisch. Dazu werden Daten im Suchindex hinzugefügt und aktualisiert, sobald sie sich in der Datenbank ändern.
Suchindexpartitionen
Ein Suchindex kann partitioniert oder nicht partitioniert sein, je nachdem, welche Art von Abfragen Sie beschleunigen möchten.
Ein Beispiel für den Einsatz eines partitionierten Index ist, wenn die Anwendung ein E-Mail-Postfach abfragt. Jede Abfrage ist auf eine bestimmte Mailbox beschränkt.
Ein Beispiel für eine unpartitionierte Abfrage ist eine Abfrage, die alle Produktkategorien in einem Produktkatalog umfasst.
Anwendungsfälle für den Suchindex
Neben der Volltextsuche unterstützen Spanner-Suchindexe Folgendes:
- Suchanfragen nach Teilstrings: Bei dieser Art von Suchanfrage wird in einem größeren Text nach einer kürzeren Zeichenfolge (dem Teilstring) gesucht.
- Bedingungen für einen beliebigen Teil der indexierten Daten, einschließlich exakter Übereinstimmungen und numerischer Werte, in einem einzigen Indexscan kombinieren.
Weitere Informationen zu Anwendungsfällen finden Sie unter Suchindexe im Vergleich zu sekundären Indexen.
Beispiel für einen Suchindex
Angenommen, es gibt eine Tabelle mit Informationen zu Musikalben:
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
AlbumTitle STRING(MAX)
) PRIMARY KEY(AlbumId);
Spanner bietet mehrere Tokenisierungsfunktionen, mit denen Tokens erstellt werden. Wenn Sie die vorherige Tabelle so ändern möchten, dass Nutzer eine Volltextsuche nach Albumtiteln durchführen können, erstellen Sie mit der Funktion TOKENIZE_FULLTEXT
Tokens aus Albumtiteln. Erstellen Sie dann eine Spalte mit dem Datentyp TOKENLIST
, um die Tokenisierungsausgabe von TOKENIZE_FULLTEXT
zu speichern. In diesem Beispiel erstellen wir die Spalte AlbumTitle_Tokens
.
ALTER TABLE Albums
ADD COLUMN AlbumTitle_Tokens TOKENLIST
AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN;
Im folgenden Beispiel wird die DDL CREATE SEARCH INDEX
verwendet, um einen Suchindex (AlbumsIndex
) für die AlbumTitle
-Tokens (AlbumTitle_Tokens
) zu erstellen:
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens);
Nachdem du den Suchindex hinzugefügt hast, kannst du mithilfe von SQL-Abfragen nach Alben suchen, die den Suchkriterien entsprechen. Beispiel:
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
Datenkonsistenz
Wenn ein Index erstellt wird, führt Spanner automatisierte Prozesse aus, um die Daten zu ergänzen und für Konsistenz zu sorgen. Wenn Schreibvorgänge bestätigt werden, werden die Indexe in derselben Transaktion aktualisiert. Spanner führt automatisch Prüfungen der Datenkonsistenz durch.
Schemadefinitionen für Suchindexe
Suchindexe werden für eine oder mehrere TOKENLIST
-Spalten einer Tabelle definiert. Suchindexe haben die folgenden Komponenten:
- Basistabelle: Die Spanner-Tabelle, die indexiert werden muss.
TOKENLIST
-Spalte: Eine Sammlung von Spalten, die die zu indexierenden Tokens definieren. Die Reihenfolge dieser Spalten ist unerheblich.
In der folgenden Anweisung ist „Albums“ beispielsweise die Basistabelle. TOKENLIST
-Spalten werden auf AlbumTitle
(AlbumTitle_Tokens
) und Rating
(Rating_Tokens
) erstellt.
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
SingerId INT64 NOT NULL,
ReleaseTimestamp INT64 NOT NULL,
AlbumTitle STRING(MAX),
Rating FLOAT64,
AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN
) PRIMARY KEY(AlbumId);
Mit der folgenden CREATE SEARCH INDEX
-Anweisung können Sie einen Suchindex mit den Tokens für AlbumTitle
und Rating
erstellen:
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens, Rating_Tokens)
PARTITION BY SingerId
ORDER BY ReleaseTimestamp DESC
Für Suchindexe stehen folgende Optionen zur Verfügung:
- Partitionen: Optionale Spaltengruppe, die den Suchindex unterteilt. Das Abfragen eines partitionierten Index ist oft deutlich effizienter als das Abfragen eines nicht partitionierten Index. Weitere Informationen finden Sie unter Partitionssuchindexe.
- Spalte für die Sortierreihenfolge: Eine optionale
INT64
-Spalte, die die Reihenfolge des Abrufs aus dem Suchindex festlegt. Weitere Informationen finden Sie unter Sortierreihenfolge des Suchindexes. - Verschachteln: Wie bei sekundären Indexen können Sie auch Suchindexe verschachteln. Interleaved-Suchindexe benötigen weniger Ressourcen für das Schreiben und den Join mit der Basistabelle. Weitere Informationen finden Sie unter Interleaved Search-Indexe.
- Options-Klausel: Eine Liste von Schlüssel/Wert-Paaren, die die Standardeinstellungen des Suchindexes überschreiben.
Weitere Informationen finden Sie in der Referenz zu CREATE SEARCH INDEX
.
Internes Layout von Suchindexen
Ein wichtiges Element der internen Darstellung von Suchindexen ist eine docid, die als speichereffiziente Darstellung des Primärschlüssels der Basistabelle dient und beliebig lang sein kann. Außerdem wird damit die Reihenfolge für das interne Datenlayout gemäß den vom Nutzer bereitgestellten ORDER BY
-Spalten der CREATE SEARCH INDEX
-Klausel erstellt. Sie wird als eine oder zwei 64‑Bit-Ganzzahlen dargestellt.
Suchindexe werden intern als zweistufige Zuordnung implementiert:
- Tokens zu Dokument-IDs
- Docids zu Primärschlüsseln der Basistabelle
Dieses Schema führt zu erheblichen Speichereinsparungen, da in Spanner nicht der vollständige Primärschlüssel der Basistabelle für jedes <token, document>
-Paar gespeichert werden muss.
Es gibt zwei Arten von physischen Indexen, die die beiden Zuordnungsebenen implementieren:
- Ein Sekundärindex, der Partitionsschlüssel und eine Dokument-ID dem Primärschlüssel der Basistabelle zuordnet. Im Beispiel im vorherigen Abschnitt wird
{SingerId, ReleaseTimestamp, uid}
so zu{AlbumId}
zugeordnet. Der sekundäre Index speichert außerdem alle Spalten, die in derSTORING
-Klausel vonCREATE SEARCH INDEX
angegeben sind. - Ein Tokenindex, der Tokens Docids zuordnet, ähnlich wie umgekehrte Indexe in der Literatur zum Informationsretrieval. Spanner verwaltet für jede
TOKENLIST
des Suchindexes einen separaten Tokenindex. Logischerweise enthalten Tokenindexe Listen mit Dokument-IDs für jedes Token in jeder Partition (in der Informationssuche als Postingslisten bezeichnet). Die Listen werden für einen schnellen Abruf nach Tokens sortiert. Innerhalb der Listen wird „docid“ für die Sortierung verwendet. Einzelne Tokenindizes sind eine Implementierungsdetail, die nicht über Spanner APIs freigegeben werden.
Spanner unterstützt die folgenden vier Optionen für „docid“.
Google-Suchindex | Docid | Verhalten |
---|---|---|
ORDER BY -Klausel für den Suchindex ausgelassen |
{uid} |
Spanner fügt jeder Zeile einen versteckten eindeutigen Wert (UID) hinzu, um sie zu identifizieren. |
ORDER BY column |
{column, uid} |
Spanner fügt die UID-Spalte als Entscheidungskriterium für Zeilen mit denselben column -Werten innerhalb einer Partition hinzu. |
ORDER BY column ... OPTIONS (disable_automatic_uid_column=true) |
{column} |
Die Spalte „UID“ wurde nicht hinzugefügt. Die column -Werte müssen innerhalb einer Partition eindeutig sein. |
ORDER BY column1, column2 ... OPTIONS (disable_automatic_uid_column=true) |
{column1, column2} |
Die Spalte „UID“ wurde nicht hinzugefügt. Die Kombination der Werte column1 und column2 muss innerhalb einer Partition eindeutig sein. |
Verwendungshinweise:
- Die Spalte „interne UID“ wird nicht über die Spanner API bereitgestellt.
- Bei Indexen, in denen die UID nicht hinzugefügt wird, schlagen Transaktionen fehl, die eine Zeile mit einer bereits vorhandenen Partitions- oder Sortierreihenfolge hinzufügen.
Betrachten Sie beispielsweise die folgenden Daten:
AlbumId | SingerId | ReleaseTimestamp | SongTitle |
---|---|---|---|
a1 | 1 | 997 | Schöne Tage |
a2 | 1 | 743 | Schöne Augen |
Angenommen, die Spalte für die Vorsortierung ist in aufsteigender Reihenfolge, wird der Inhalt des Tokenindexes nach SingerId
so partitioniert:
SingerId | _token | ReleaseTimestamp | uid |
---|---|---|---|
1 | schön | 743 | uid1 |
1 | schön | 997 | uid2 |
1 | Tage | 743 | uid1 |
1 | Augen | 997 | uid2 |
Sharding des Suchindexes
Wenn Spanner eine Tabelle teilt, werden Suchindexdaten so verteilt, dass sich alle Tokens in einer bestimmten Basistabellenzeile im selben Split befinden. Mit anderen Worten: Der Suchindex ist nach Dokumenten aufgeteilt. Diese Sharding-Strategie hat erhebliche Auswirkungen auf die Leistung:
- Die Anzahl der Server, mit denen jede Transaktion kommuniziert, bleibt unabhängig von der Anzahl der Tokens oder der Anzahl der indexierten
TOKENLIST
-Spalten konstant. - Suchanfragen mit mehreren bedingten Ausdrücken werden unabhängig voneinander für jede Teilung ausgeführt. So wird der Leistungsoverhead vermieden, der mit einem verteilten Join verbunden ist.
Suchindexe haben zwei Bereitstellungsmodi:
- Einheitliche Sharding (Standardeinstellung). Bei der einheitlichen Sharding-Methode werden indexierte Daten für jede Zeile der Basistabelle zufällig einem Index-Split einer Partition zugewiesen.
- Sortierreihenfolge-Sharding Beim Sortierungsreihenfolge-Sharding werden die Daten jeder Zeile der Basistabelle basierend auf den
ORDER BY
-Spalten einem Index-Split einer Partition zugewiesen. Bei einer absteigenden Sortierreihenfolge werden beispielsweise alle Zeilen mit den höchsten Sortierreihenfolgewerten im ersten Indexsplit einer Partition und die nächsthöhere Gruppe von Sortierreihenfolgewerten im nächsten Split angezeigt.
Bei diesen Sharding-Modi besteht ein Kompromiss zwischen den Hotspot-Risiken und den Abfragekosten:
- Bei nach Sortierungsreihenfolge shardeten Suchindexen kommt es häufig zu Hotspots, wenn der Index nach einem Zeitstempel sortiert wird. Weitere Informationen finden Sie unter Primärschlüssel auswählen, um Hotspots zu vermeiden. Wenn die Schreiblast hingegen für eine Reihe von Dokumenten zunimmt, sorgt das einheitliche Sharding dafür, dass die Zunahme gleichmäßig auf die Shards verteilt wird.
- Bei der standardmäßigen lastbasierten Aufteilung werden zusätzliche Aufteilungen erstellt, die einen angemessenen Schutz vor Hotspots bieten. Der Nachteil des einheitlichen Sharding besteht darin, dass für einige Arten von Abfragen möglicherweise mehr Ressourcen benötigt werden.
Der Sharding-Modus eines Suchindexes wird mit der OPTIONS
-Klausel konfiguriert:
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens, Rating_Tokens)
PARTITION BY SingerId
ORDER BY ReleaseTimestamp DESC
OPTIONS (sort_order_sharding = true);
Wenn sort_order_sharding=false
festgelegt oder nicht angegeben ist, wird der Suchindex mit einheitlichem Sharding erstellt.
Verschränkte Suchindexe
Wie bei sekundären Indexen können Sie Suchindexe in einer übergeordneten Tabelle der Basistabelle verschachteln. Der Hauptgrund für die Verwendung von verschränkten Suchindexen besteht darin, Basistabellendaten mit Indexdaten für kleine Partitionen zusammenzuführen. Diese opportunistische Colocation bietet folgende Vorteile:
- Für Schreibvorgänge ist kein zweiphasiger Commit erforderlich.
- Rückverknüpfungen des Suchindexes mit der Basistabelle werden nicht verteilt.
Für interleaved Suchindexe gelten die folgenden Einschränkungen:
- Nur nach Sortierreihenfolge shardete Indexe können verschachtelt werden.
- Suchindexe können nur in Tabellen der obersten Ebene, nicht in untergeordneten Tabellen, verschachtelt werden.
- Wie bei verschachtelten Tabellen und sekundären Indexen muss der Schlüssel der übergeordneten Tabelle ein Präfix der
PARTITION BY
-Spalten im verschachtelten Suchindex sein.
Verschränkten Suchindex definieren
Im folgenden Beispiel wird gezeigt, wie ein Index für die Zwischenspeicherung von Suchanfragen definiert wird:
CREATE TABLE Singers (
SingerId INT64 NOT NULL
) PRIMARY KEY(SingerId);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId STRING(MAX) NOT NULL,
AlbumTitle STRING(MAX),
AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN
) PRIMARY KEY(SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
PARTITION BY SingerId,
INTERLEAVE IN Singers
OPTIONS (sort_order_sharding = true);
Sortierreihenfolge des Suchindex
Die Anforderungen an die Definition der Sortierreihenfolge des Suchindexes unterscheiden sich von denen für sekundäre Indexe.
Betrachten Sie beispielsweise die folgende Tabelle:
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
ReleaseTimestamp INT64 NOT NULL,
AlbumName STRING(MAX),
AlbumName_Token TOKENLIST AS (TOKEN(AlbumName)) HIDDEN
) PRIMARY KEY(AlbumId);
Die Anwendung kann einen sekundären Index definieren, um Informationen mithilfe der AlbumName
nach ReleaseTimestamp
zu suchen:
CREATE INDEX AlbumsSecondaryIndex ON Albums(AlbumName, ReleaseTimestamp DESC);
Der entsprechende Suchindex sieht so aus (hier wird die Tokenisierung mit exakter Übereinstimmung verwendet, da sekundäre Indexe keine Volltextsuche unterstützen):
CREATE SEARCH INDEX AlbumsSearchIndex
ON Albums(AlbumName_Token)
ORDER BY ReleaseTimestamp DESC;
Die Sortierreihenfolge des Suchindexes muss die folgenden Anforderungen erfüllen:
- Verwenden Sie nur
INT64
-Spalten für die Sortierreihenfolge eines Suchindexes. Spalten mit beliebiger Größe belegen zu viele Ressourcen im Suchindex, da Spanner neben jedem Token eine DocID speichern muss. Insbesondere kann der TypTIMESTAMP
nicht für die Spalte „Sortierreihenfolge“ verwendet werden, daTIMESTAMP
eine Nanosekundengenauigkeit verwendet, die nicht in eine 64‑Bit-Ganzzahl passt. Spalten für die Sortierreihenfolge dürfen nicht
NULL
sein. Es gibt zwei Möglichkeiten, diese Anforderung zu erfüllen:- Deklarieren Sie die Spalte für die Sortierreihenfolge als
NOT NULL
. - Konfigurieren Sie den Index so, dass NULL-Werte ausgeschlossen werden.
- Deklarieren Sie die Spalte für die Sortierreihenfolge als
Häufig wird ein Zeitstempel verwendet, um die Sortierreihenfolge zu bestimmen. Häufig werden für solche Zeitstempel Mikrosekunden seit der Unix-Epoche verwendet.
In der Regel rufen Anwendungen die neuesten Daten zuerst mithilfe eines Suchindexes ab, der in absteigender Reihenfolge sortiert ist.
Suchindexe mit NULL-Filter
Mit der WHERE column IS NOT NULL
-Syntax können Sie Zeilen der Basistabelle aus Suchindexen ausschließen. NULL-Filter können auf Partitionsschlüssel, Sortierreihenfolgespalten und gespeicherte Spalten angewendet werden. Das Filtern nach NULL für gespeicherte Arrayspalten ist nicht zulässig.
Beispiel
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING (Genre)
WHERE Genre IS NOT NULL
In der Abfrage muss die NULL-Filterbedingung (Genre IS NOT NULL
in diesem Beispiel) in der WHERE
-Klausel angegeben sein. Andernfalls kann der Abfrageoptimierer den Suchindex nicht verwenden. Weitere Informationen finden Sie unter Anforderungen an SQL-Abfragen.
Verwenden Sie den NULL-Filter für eine generierte Spalte, um Zeilen basierend auf beliebigen Kriterien auszuschließen. Weitere Informationen finden Sie unter Teilindex mithilfe einer generierten Spalte erstellen.
Nächste Schritte
- Weitere Informationen zur Tokenisierung und zu Spanner-Tokenisierern
- Weitere Informationen zu numerischen Indexen
- Weitere Informationen zur Indexpartitionierung