Auf dieser Seite wird beschrieben, wie Sie eine unscharfe Suche im Rahmen einer Volltextsuche verwenden.
Neben der genauen Tokensuche mit den Funktionen SEARCH und SEARCH_SUBSTRING unterstützt Spanner auch ungefähre (oder unscharfe) Suchvorgänge. Bei unscharfen Suchanfragen werden übereinstimmende Dokumente gefunden, obwohl es geringfügige Unterschiede zwischen der Anfrage und dem Dokument gibt.
Spanner unterstützt die folgenden Arten von unscharfer Suche:
- Ungefähre Suche auf Grundlage von N-Grammen
- Phonetische Suche mit Soundex
N-Gramm-basierte ungefähre Suche verwenden
Die auf N-Grammen basierende unscharfe Suche basiert auf derselben Teilstring-Tokenisierung, die für eine Teilstring-Suche erforderlich ist. Die Konfiguration des Tokenizers ist wichtig, da sie sich auf die Suchqualität und ‑leistung auswirkt. Im folgenden Beispiel wird gezeigt, wie Sie eine Anfrage mit falsch geschriebenen oder unterschiedlich geschriebenen Wörtern erstellen, um ungefähre Übereinstimmungen im Suchindex zu finden.
Schema
GoogleSQL
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
AlbumTitle STRING(MAX),
AlbumTitle_Tokens TOKENLIST AS (
TOKENIZE_SUBSTRING(AlbumTitle, ngram_size_min=>2, ngram_size_max=>3,
relative_search_types=>["word_prefix", "word_suffix"])) HIDDEN
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING (AlbumTitle);
PostgreSQL
In diesem Beispiel wird spanner.tokenize_substring verwendet.
CREATE TABLE albums (
albumid character varying NOT NULL,
albumtitle character varying,
albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (
spanner.tokenize_substring(albumtitle, ngram_size_min=>2, ngram_size_max=>3,
relative_search_types=>'{word_prefix, word_suffix}'::text[])) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex
ON albums(albumtitle_tokens)
INCLUDE (albumtitle);
Abfrage
Mit der folgenden Abfrage werden die Alben mit Titeln gefunden, die „Hatel Kaliphorn“ am ähnlichsten sind, z. B. „Hotel California“.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn")
ORDER BY SCORE_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn") DESC
LIMIT 10
PostgreSQL
In diesem Beispiel werden spanner.score_ngrams und spanner.search_ngrams verwendet.
SELECT albumid
FROM albums
WHERE spanner.search_ngrams(albumtitle_tokens, 'Hatel Kaliphorn')
ORDER BY spanner.score_ngrams(albumtitle_tokens, 'Hatel Kaliphorn') DESC
LIMIT 10
Leistung und Erinnerung für eine auf N-Grammen basierende ungefähre Suche optimieren
Die Beispielabfrage im vorherigen Abschnitt führt die Suche in zwei Phasen mit zwei verschiedenen Funktionen durch:
SEARCH_NGRAMSfindet alle infrage kommenden Alben, die gemeinsame N-Gramme mit der Suchanfrage haben. Beispiele: Dreistellige N-Gramme für „California“ sind[cal, ali, lif, ifo, for, orn, rni, nia]und für „Kaliphorn“[kal, ali, lip, iph, pho, hor, orn]. Die freigegebenen N-Gramme in diesen Datasets sind[ali, orn]. Standardmäßig werden mitSEARCH_NGRAMSalle Dokumente mit mindestens zwei gemeinsamen N-Grammen abgeglichen. Daher wird „Kaliphorn“ mit „California“ abgeglichen.SCORE_NGRAMSsortiert Ergebnisse nach Ähnlichkeit. Die Ähnlichkeit zweier Strings wird als Verhältnis von unterschiedlichen gemeinsamen N‑Grammen zu unterschiedlichen nicht gemeinsamen N‑Grammen definiert:
Normalerweise ist die Suchanfrage für die Funktionen SEARCH_NGRAMS und SCORE_NGRAMS identisch. Die empfohlene Vorgehensweise ist, das Argument mit Abfrageparametern anstelle von Stringliteralen zu verwenden und denselben Abfrageparameter in den Funktionen SEARCH_NGRAMS und SCORE_NGRAMS anzugeben.
Spanner hat drei Konfigurationsargumente, die mit SEARCH_NGRAMS verwendet werden können:
- Die Mindest- und Höchstgrößen für N-Gramme werden mit den Funktionen
TOKENIZE_SUBSTRINGoderTOKENIZE_NGRAMSangegeben. Wir raten von N-Grammen mit einem Zeichen ab, da sie mit einer sehr großen Anzahl von Dokumenten übereinstimmen könnten. Andererseits führen lange N-Gramme dazu, dassSEARCH_NGRAMSkurze falsch geschriebene Wörter nicht erkennt. - Die Mindestanzahl von N-Grammen, die mit
SEARCH_NGRAMSübereinstimmen müssen (mit den Argumentenmin_ngramsundmin_ngrams_percentinSEARCH_NGRAMSfestgelegt). Höhere Zahlen beschleunigen die Abfrage in der Regel, verringern aber den Recall.
Um ein gutes Gleichgewicht zwischen Leistung und Recall zu erreichen, können Sie diese Argumente an die jeweilige Anfrage und Arbeitslast anpassen.
Wir empfehlen außerdem, einen inneren LIMIT einzufügen, um sehr teure Anfragen zu vermeiden, wenn eine Kombination aus beliebten N-Grammen gefunden wird.
GoogleSQL
SELECT AlbumId
FROM (
SELECT AlbumId,
SCORE_NGRAMS(AlbumTitle_Tokens, @p) AS score
FROM Albums
WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, @p)
LIMIT 10000 # inner limit
)
ORDER BY score DESC
LIMIT 10 # outer limit
PostgreSQL
In diesem Beispiel werden spanner.score_ngrams und spanner.search_ngrams verwendet.
Der Abfrageparameter $1 ist an „Hatel Kaliphorn“ gebunden.
SELECT albumid
FROM
(
SELECT albumid, spanner.score_ngrams(albumtitle_tokens, $1) AS score
FROM albums
WHERE spanner.search_ngrams(albumtitle_tokens, $1)
LIMIT 10000
) AS inner_query
ORDER BY inner_query.score DESC
LIMIT 10
N-Gramm-basierte unscharfe Suche im Vergleich zum erweiterten Anfragemodus
Neben der N-Gramm-basierten Fuzzy-Suche werden im erweiterten Anfragemodus auch einige falsch geschriebene Wörter berücksichtigt. Daher gibt es einige Überschneidungen zwischen den beiden Funktionen. In der folgenden Tabelle werden die Unterschiede zusammengefasst:
| Fuzzy-Suche auf Grundlage von N-Grammen | Erweiterter Abfragemodus | |
| Kosten | Erfordert eine teurere Substring-Tokenisierung auf Grundlage von N-Grammen | Erfordert eine kostengünstigere Volltext-Tokenisierung |
| Suchanfragetypen | Funktioniert gut bei kurzen Dokumenten mit wenigen Wörtern, z. B. bei einem Personennamen, einem Städtenamen oder einem Produktnamen | Funktioniert gleichermaßen gut mit Dokumenten und Suchanfragen jeder Größe |
| Suche nach Wortteilen | Führt eine Teilstring-Suche durch, bei der Rechtschreibfehler berücksichtigt werden | Unterstützt nur die Suche nach ganzen Wörtern (SEARCH_SUBSTRING unterstützt das Argument enhance_query nicht).
|
| Falsch geschriebene Wörter | Unterstützt falsch geschriebene Wörter im Index oder in der Abfrage | Unterstützt nur falsch geschriebene Wörter in der Anfrage |
| Korrekturen | Findet alle falsch geschriebenen Übereinstimmungen, auch wenn es sich bei der Übereinstimmung nicht um ein echtes Wort handelt | Korrigiert Rechtschreibfehler bei häufigen, bekannten Wörtern |
Phonetische Suche mit Soundex durchführen
Spanner bietet die Funktion SOUNDEX, mit der Sie Wörter finden können, die unterschiedlich geschrieben, aber gleich ausgesprochen werden. Beispiel: SOUNDEX("steven"), SOUNDEX("stephen") und SOUNDEX("stefan") sind alle „s315“, während SOUNDEX("stella") „s340“ ist. Bei SOUNDEX wird zwischen Groß- und Kleinschreibung unterschieden und es funktioniert nur für lateinische Alphabete.
Die phonetische Suche mit SOUNDEX kann mit einer generierten Spalte und einem Suchindex implementiert werden, wie im folgenden Beispiel gezeigt:
GoogleSQL
CREATE TABLE Singers (
SingerId INT64,
AlbumTitle STRING(MAX),
AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
Name STRING(MAX),
NameSoundex STRING(MAX) AS (LOWER(SOUNDEX(Name))),
NameSoundex_Tokens TOKENLIST AS (TOKEN(NameSoundex)) HIDDEN
) PRIMARY KEY(SingerId);
CREATE SEARCH INDEX SingersPhoneticIndex ON Singers(AlbumTitle_Tokens, NameSoundex_Tokens);
PostgreSQL
In diesem Beispiel wird spanner.soundex verwendet.
CREATE TABLE singers (
singerid bigint,
albumtitle character varying,
albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
name character varying,
namesoundex character varying GENERATED ALWAYS AS (lower(spanner.soundex(name))) VIRTUAL,
namesoundex_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.token(lower(spanner.soundex(name))) VIRTUAL HIDDEN,
PRIMARY KEY(singerid));
CREATE SEARCH INDEX singersphoneticindex ON singers(albumtitle_tokens, namesoundex_tokens);
Die folgende Abfrage ordnet „stefan“ auf SOUNDEX „Steven“ zu und enthält AlbumTitle mit „cat“:
GoogleSQL
SELECT SingerId
FROM Singers
WHERE NameSoundex = LOWER(SOUNDEX("stefan")) AND SEARCH(AlbumTitle_Tokens, "cat")
PostgreSQL
SELECT singerid
FROM singers
WHERE namesoundex = lower(spanner.soundex('stefan')) AND spanner.search(albumtitle_tokens, 'cat')
Nächste Schritte
- Weitere Informationen zur Tokenisierung und zu Spanner-Tokenizern
- Weitere Informationen zu Suchindexen
- Weitere Informationen zu Volltextsuchanfragen