Cette page décrit la fonction SEARCH et le mode requête amélioré, qui sont utilisés pour effectuer des requêtes de recherche en texte intégral sur les tables Spanner.
Interroger un index de recherche
Spanner fournit la fonction SEARCH à utiliser pour les requêtes d'index de recherche. Un cas d'utilisation typique serait une application dans laquelle les utilisateurs saisissent du texte dans un champ de recherche et où l'application envoie la saisie de l'utilisateur directement dans la fonction SEARCH. La fonction SEARCH utiliserait ensuite un index de recherche pour trouver ce texte.
La fonction SEARCH nécessite deux arguments :
- Nom d'un index de recherche
- Une requête de recherche
La fonction SEARCH ne fonctionne que lorsqu'un index de recherche est défini. La fonction SEARCH peut être combinée à n'importe quelle construction SQL arbitraire, comme des filtres, des agrégations ou des jointures.
La fonction SEARCH ne peut pas être utilisée avec les requêtes de transaction.
La requête suivante utilise la fonction SEARCH pour renvoyer tous les albums dont le titre contient friday ou monday :
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')
PostgreSQL
Cet exemple utilise spanner.search.
SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'friday OR monday')
Requête de recherche
Les requêtes de recherche utilisent la syntaxe raw search query (requête de recherche brute) par défaut. Vous pouvez spécifier d'autres syntaxes à l'aide de l'argument SEARCH
dialect.
Dialecte rquery
Le dialecte par défaut est raw search query. Spanner utilise un langage spécifique au domaine (DSL) appelé rquery.
Le langage rquery suit les mêmes règles que le tokeniseur de texte brut lorsqu'il divise la requête de recherche saisie en termes distincts. Cela inclut la segmentation des langues asiatiques.
Pour en savoir plus sur l'utilisation de rquery, consultez la syntaxe rquery.
dialecte des mots
Le dialecte de mots est semblable à rquery, mais plus simple. Il n'utilise aucun opérateur spécial. Par exemple, OR est traité comme un terme de recherche au lieu d'un opérateur de disjonction. Les guillemets doubles sont traités comme de la ponctuation plutôt que comme une recherche d'expression et sont ignorés.
Avec le mot "dialecte", AND est appliqué implicitement à tous les termes et est requis lors de la mise en correspondance. Il suit les mêmes règles que le tokenizer en texte brut pour diviser la requête de recherche saisie en termes.
Pour en savoir plus sur l'utilisation du dialecte "words", consultez la syntaxe "words".
dialecte words_phrase
Le dialecte words_phrase n'utilise aucun opérateur spécial. Tous les termes sont traités comme une expression, ce qui signifie qu'ils doivent être adjacents et dans l'ordre spécifié.
Comme pour rquery, le dialecte words_phrase suit les mêmes règles que le tokenizer en texte brut pour diviser la requête de recherche saisie en termes.
Pour en savoir plus sur l'utilisation du dialecte "words_phrase", consultez la syntaxe de "words_phrase".
Mode Requête améliorée
Spanner propose deux modes de recherche en texte intégral : une recherche de base basée sur des jetons et un mode plus avancé appelé enhance_query. Lorsqu'elle est activée, enhance_query élargit la requête de recherche pour inclure des termes associés et des synonymes, ce qui augmente la probabilité de trouver des résultats pertinents.
Pour activer cette option, définissez l'argument facultatif enhance_query=>true dans la fonction SEARCH. Par exemple, la requête de recherche hotl cal correspond à l'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)
Le mode enhance_query est une option au moment de l'exécution de la requête. Cela n'a aucune incidence sur la tokenisation.
Vous pouvez utiliser le même index de recherche avec ou sans enhance_query.
Google améliore en permanence les algorithmes d'amélioration des requêtes. Par conséquent, une requête avec enhance_query == true peut générer des résultats légèrement différents au fil du temps.
Lorsque le mode enhance_query est activé, le nombre de termes recherchés par la fonction SEARCH peut augmenter, ce qui peut légèrement accroître la latence.
Exigences concernant les requêtes SQL
Pour qu'une requête SQL puisse utiliser un index de recherche, elle doit remplir plusieurs conditions. Si ces conditions ne sont pas remplies, la requête utilise un autre plan de requête ou échoue si aucun plan alternatif n'existe.
Les requêtes doivent répondre aux conditions suivantes :
Les fonctions SEARCH et
SEARCH_SUBSTRINGnécessitent un index de recherche. Spanner n'est pas compatible avec ces fonctions dans les requêtes sur la table de base ou les index secondaires.Les index partitionnés doivent avoir toutes les colonnes de partition liées par une condition d'égalité dans la clause
WHEREde la requête.Par exemple, si un index de recherche est défini sur
PARTITION BY x, y, la requête doit comporter une conjonction dans la clauseWHEREdex = <parameter or constant> AND y = <parameter or constant>. Cet index de recherche n'est pas pris en compte par l'optimiseur de requêtes si une telle condition est manquante.Toutes les colonnes
TOKENLISTréférencées par les opérateursSEARCHetSEARCH_SUBSTRINGdoivent être indexées dans le même index de recherche.Par exemple, prenons la définition de table et d'index suivante :
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);La requête suivante échoue, car il n'existe aucun index de recherche unique qui indexe à la fois
AlbumTitle_TokensetAlbumStudio_Tokens:GoogleSQL
SELECT AlbumId FROM Albums WHERE SEARCH(AlbumTitle_Tokens, @p1) AND SEARCH(AlbumStudio_Tokens, @p2)PostgreSQL
Cet exemple utilise les paramètres de requête
$1et$2, qui sont liés respectivement à "fast car" et "blue note".SELECT albumid FROM albums WHERE spanner.search(albumtitle_tokens, $1) AND spanner.search(albumstudio_tokens, $2)Si la colonne d'ordre de tri est nullable, le schéma et la requête doivent exclure les lignes où la colonne d'ordre de tri est NULL. Pour en savoir plus, consultez Ordre de tri des index de recherche.
Si l'index de recherche est filtré sur NULL, la requête doit inclure la même expression de filtrage NULL que celle utilisée dans un index. Pour en savoir plus, consultez Index de recherche filtrés par NULL.
Les index de recherche et les fonctions de recherche ne sont pas compatibles avec le LMD, le LMD partitionné ni les requêtes partitionnées.
Les index de recherche et les fonctions de recherche sont généralement utilisés dans les transactions en lecture seule. Si les exigences de l'application autorisent les résultats obsolètes, vous pourrez peut-être améliorer la latence en exécutant des requêtes de recherche avec une durée d'obsolescence de 10 secondes ou plus. Pour en savoir plus, consultez Lire des données obsolètes. Cela est particulièrement utile pour les requêtes de recherche qui s'étendent à de nombreuses partitions d'index.
Les index de recherche et les fonctions de recherche ne sont pas recommandés dans les transactions en lecture/écriture.
Lors de l'exécution, les requêtes de recherche verrouillent une partition d'index entière. Par conséquent, un taux élevé de requêtes de recherche dans les transactions en lecture/écriture peut entraîner des conflits de verrouillage, ce qui peut entraîner des pics de latence. Par défaut, les index de recherche ne sont pas sélectionnés automatiquement dans les transactions en lecture-écriture. Si une requête est forcée d'utiliser un index de recherche dans une transaction en lecture/écriture, elle échoue par défaut. Elle échoue également si la requête contient l'une des fonctions de recherche. Ce comportement peut être remplacé par l'indication @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} au niveau de l'instruction GoogleSQL (mais les requêtes restent sujettes aux conflits de verrouillage).
Une fois les conditions d'éligibilité à l'index remplies, l'optimiseur de requêtes tente d'accélérer les conditions de requête non textuelles (comme Rating > 4). Si l'index de recherche n'inclut pas la colonne TOKENLIST appropriée, la condition n'est pas accélérée et reste une condition résiduelle.
Paramètres de requête
Les arguments de requête de recherche sont spécifiés sous la forme d'un littéral ou d'un paramètre de requête. Nous vous recommandons d'utiliser des paramètres de requête pour la recherche en texte intégral plutôt que des littéraux de chaîne lorsque les arguments autorisent la valeur du paramètre de requête.
Sélection de l'index
Spanner sélectionne généralement l'index le plus efficace pour une requête à l'aide de la modélisation basée sur les coûts. Toutefois, l'indication FORCE_INDEX demande explicitement à Spanner d'utiliser un index de recherche spécifique. Par exemple, le code suivant montre comment forcer Spanner à utiliser AlbumsIndex :
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')
Si l'index de recherche spécifié n'est pas éligible, la requête échoue, même s'il existe d'autres index de recherche éligibles.
Extraits dans les résultats de recherche
Un extrait est un fragment de texte extrait d'une chaîne donnée. Il permet aux utilisateurs de se faire une idée du contenu d'un résultat de recherche et de la raison pour laquelle il est pertinent par rapport à leur requête.
Par exemple, Gmail utilise des extraits pour indiquer la partie d'un e-mail qui correspond à la requête de recherche :

Le fait que la base de données génère un extrait présente plusieurs avantages :
- Praticité : vous n'avez pas besoin d'implémenter de logique pour générer des extraits à partir d'une requête de recherche.
- Efficacité : les extraits réduisent la taille de la sortie du serveur.
La fonction SNIPPET crée l'extrait. Elle renvoie la partie pertinente de la valeur de chaîne d'origine, ainsi que les positions des caractères à mettre en évidence. Le client peut ensuite choisir comment afficher l'extrait à l'utilisateur final (par exemple, en utilisant du texte en surbrillance ou en gras).
Par exemple, la commande suivante utilise SNIPPET pour récupérer du texte à partir de AlbumTitle :
GoogleSQL
SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")
PostgreSQL
Cet exemple utilise spanner.snippet.
SELECT albumid, spanner.snippet(albumtitle, 'Fast Car')
FROM albums
WHERE spanner.search(albumtitle_tokens, 'Fast Car')
Étapes suivantes
- Découvrez comment classer les résultats de recherche.
- Découvrez comment effectuer une recherche de sous-chaîne.
- Découvrez comment paginer les résultats de recherche.
- Découvrez comment combiner des requêtes en texte intégral et non textuelles.
- Découvrez comment effectuer une recherche dans plusieurs colonnes.