Suchindexe

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. Index aktualisieren Verwenden Sie die DDL-Anweisung ALTER SEARCH INDEX. Spanner der Suchindex automatisch erstellt und verwaltet, einschließlich Daten im Suchindex aktualisieren, sobald sie sich in der Datenbank ändern.

Partitionen von Suchindexen

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 Suchindexe

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 eine Teilmenge der indexierten Daten in einem einzigen Indexscan kombinieren.

Suchindexe unterstützen die Indexierung von nicht textbasierten Daten wie Zahlen und suchen, besteht der häufigste Anwendungsfall für einen Suchindex darin, Text in einem Dokument.

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, verwenden Sie die Funktion TOKENIZE_FULLTEXT, um Tokens aus Albumtiteln zu erstellen. 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);

Verwenden Sie nach dem Hinzufügen des Suchindex SQL-Abfragen, um passende Alben zu finden. die Suchkriterien. 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 Indexsuche

Suchindexe werden in einer oder mehreren TOKENLIST-Spalten einer Tabelle definiert. Suchindexe haben die folgenden Komponenten:

  • Basistabelle: die Spanner-Tabelle, die indexiert werden muss.
  • Spalte TOKENLIST: Eine Sammlung von Spalten, die die Tokens definieren die indexiert werden müssen. Die Reihenfolge dieser Spalten ist unerheblich.

In der folgenden Anweisung lautet die Basistabelle beispielsweise Albums. 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

Suchindexe haben die folgenden Optionen:

  • Partitionen: Optionale Spaltengruppe, die den Suchindex unterteilt. Die Abfrage eines partitionierten Index ist oft wesentlich effizienter als einen nicht partitionierten Index abfragen. Weitere Informationen finden Sie unter Partitionssuchindexe
  • Sortierspalte: Eine optionale Spalte INT64, die legt die Reihenfolge fest, in der Daten aus dem Suchindex abgerufen werden. Weitere Informationen finden Sie unter Sortierreihenfolge des Suchindex.
  • Verschachteln: Wie bei sekundären Indexen können Sie auch Suchindexe verschachteln. Verschränkte Suchindexe benötigen weniger Ressourcen für das Schreiben und Verknüpfen mit dem Basistabelle. Weitere Informationen finden Sie unter Interleaved Search-Indexe.
  • Optionsklausel: Eine Liste von Schlüssel/Wert-Paaren, die den Standardwert überschreibt Einstellungen des Suchindex.

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 ganze 64-Bit-Zahlen dargestellt.

Suchindexe werden intern als Zuordnung auf zwei Ebenen implementiert:

  1. Tokens für Docids
  2. Dokument-IDs für Primärschlüssel der Basistabellen

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 Ebenen Zuordnung:

  1. Sekundärer Index, der Partitionsschlüssel und eine Docid der Basistabelle zuordnet Primärschlüssel. Im Beispiel im vorherigen Abschnitt wird {SingerId, ReleaseTimestamp, uid} so zu {AlbumId} zugeordnet. Der sekundäre Index speichert alle in der STORING-Klausel von CREATE SEARCH INDEX angegebenen Spalten.
  2. Tokenindexe, die Tokens Docids zuordnen, ähnlich wie invertierte Indexe in Literatur für das Informationsabrufen. Spanner unterhält eine separater Tokenindex für jede TOKENLIST des Suchindex. 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 Tokenindexe sind ein Implementierungsdetail, das nicht über Spanner APIs

Spanner unterstützt die folgenden vier Optionen für „docid“.

Google-Suchindex Docid Verhalten
Die ORDER BY-Klausel wird für den Suchindex weggelassen {uid} Spanner fügt einen ausgeblendeten eindeutigen Wert (UID) hinzu, um jede Zeile zu identifizieren.
ORDER BY column {column, uid} Spanner fügt die UID-Spalte als Entscheidungskriterium zwischen 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 aus column1- und column2-Werten 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, der nach SingerId partitioniert ist, auf folgende Weise partitioniert:

SingerId _token ReleaseTimestamp uid
1 schön 743 uid1
1 schön 997 uid2
1 Tage 743 uid1
1 Augen 997 uid2

Fragmentierung des Suchindex

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 dokumentenfragmentiert. Diese Fragmentierungsstrategie hat erhebliche Auswirkungen auf die Leistung:

  1. 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.
  2. 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 Fragmentierung werden die Basistabellenzeile wird einer Indexaufteilung einer Partition zufällig zugewiesen.
  • Sortierreihenfolge-Sharding Bei der Sortierreihenfolge werden Daten für jede Basistabellenzeile wird einer Indexaufteilung einer Partition basierend auf dem ORDER BY zugewiesen Spalten. 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 Sortierreihenfolge 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 jedoch die Schreiblast für eine Reihe von Dokumenten zunimmt, Mit gleichmäßiger Fragmentierung wird sichergestellt, dass die Erhöhung gleichmäßig über Shards.
  • Bei der standardmäßigen lastbasierten Aufteilung werden zusätzliche Aufteilungen erstellt, einen angemessenen Schutz vor Heißlaufen. Der Nachteil der einheitlichen Fragmentierung ist, dass sie für einige Abfragetypen mehr Ressourcen verwenden kann.

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, ist der Suchindex mit einheitlicher Fragmentierung erstellt.

Verschränkte Suchindexe

Wie bei sekundären Indexen können Sie Suchindexe übergeordnete Tabelle der Basistabelle. Hauptgrund für die Verwendung der verschachtelten Suche Indizes besteht darin, Basistabellendaten mit Indexdaten für kleine Partitionen zu ordnen. Diese opportunistische Colocation hat folgende Vorteile:

  • Für Schreibvorgänge ist kein zweiphasiger Commit erforderlich.
  • Back-Joins des Suchindexes mit der Basistabelle werden nicht verteilt.

Für verschränkte Suchindexe gelten die folgenden Einschränkungen:

  1. Nur Sortierreihenfolge fragmentiert Indexe überlappen lassen.
  2. Suchindizes können nur in Tabellen der obersten Ebene verschränkt sein (nicht in untergeordneten Tabellen).
  3. 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

Das folgende Beispiel zeigt, wie ein verschränkter Suchindex 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.

Sehen Sie sich zum Beispiel die folgende Tabelle an:

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:

  1. 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 für die Spalte „Sortierreihenfolge“ der Typ TIMESTAMP nicht verwendet werden, da TIMESTAMP eine Nanosekundengenauigkeit verwendet, die nicht in eine 64‑Bit-Ganzzahl passt.
  2. Spalten für die Sortierreihenfolge dürfen nicht NULL sein. Dafür gibt es zwei Möglichkeiten: Anforderung:

    1. Geben Sie die Spalte für die Sortierreihenfolge als NOT NULL an.
    2. Konfigurieren Sie den Index so, dass NULL-Werte ausgeschlossen werden.

Die Sortierreihenfolge wird häufig anhand eines Zeitstempels festgelegt. Häufig werden für solche Zeitstempel Mikrosekunden seit der Unix-Epoche verwendet.

In der Regel rufen Anwendungen die neuesten Daten zuerst ab, indem sie einen Suchindex verwenden, der in absteigender Reihenfolge sortiert ist.

Nach NULL gefilterte Suchindexe

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. NULL-Filterung nach gespeicherten Arrayspalten Zulässig sind.

Beispiel

CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING Genre
WHERE Genre IS NOT NULL

In der Abfrage muss die NULL-Filterbedingung angegeben werden (Genre IS NOT NULL für in diesem Beispiel) in der WHERE-Klausel. Andernfalls kann die Abfrageoptimierung um den Suchindex zu verwenden. Weitere Informationen finden Sie unter Anforderungen an SQL-Abfragen.

Verwenden Sie den NULL-Filter für eine generierte Spalte, um Zeilen basierend auf Kriterien erfüllen. Weitere Informationen finden Sie unter Teilindex mithilfe eines generierten Spalte.

Nächste Schritte