Cette page décrit la fonction SEARCH et ses différentes fonctionnalités avancées, qui sont
utilisées pour effectuer des requêtes de recherche en texte intégral
sur des tables Spanner.
Interroger un index de recherche
Spanner fournit la SEARCH
fonction à utiliser pour les requêtes d'index de recherche. Un cas d'utilisation possible est une application dans laquelle les utilisateurs saisissent du texte dans un champ de recherche et l'application envoie directement la saisie de l'utilisateur à la fonction SEARCH. La fonction SEARCH utilise ensuite un index de recherche pour trouver ce texte.
La fonction SEARCH nécessite deux arguments :
- Nom d'un index de recherche
- 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 avec n'importe quelle construction SQL arbitraire, telle que des filtres, des agrégations ou des jointures.
La fonction SEARCH ne peut pas être utilisée avec des 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 de requête de recherche brute
par
défaut. D'autres syntaxes peuvent être spécifiées à l'aide de l'argument SEARCH
dialect.
Dialecte rquery
Le dialecte par défaut est la requête de recherche brute. Spanner utilise un langage spécifique au domaine (DSL, domain-specific language) appelé rquery.
Le langage rquery suit les mêmes règles que le tokenizer en texte brut lors de la division de la requête de recherche d'entrée en termes distincts. Cela inclut la segmentation des langues asiatiques.
Pour en savoir plus sur l'utilisation de rquery, consultez la section Syntaxe rquery.
Dialecte words
Le dialecte words 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 des signes de ponctuation plutôt que comme une recherche d'expression et sont ignorés.
Avec le dialecte words, AND est appliqué implicitement à tous les termes et est obligatoire lors de la mise en correspondance. Il suit les mêmes règles que le tokenizer en texte brut lors de la division de la requête de recherche d'entrée en termes.
Pour en savoir plus sur l'utilisation du dialecte words, consultez la section words syntax.
Dialecte words_phrase
Le dialecte words_phrase n'utilise aucun opérateur spécial et tous les termes sont traités comme une expression, ce qui signifie qu'ils doivent être adjacents et dans l'ordre spécifié.
Comme rquery, le dialecte words_phrase suit les mêmes règles que le tokenizer en texte brut lors de la division de la requête de recherche d'entrée en termes.
Pour en savoir plus sur l'utilisation du dialecte words_phrase, consultez la section Syntaxe de l'expression words.
Élargir les requêtes de recherche pour augmenter le nombre de résultats associés
Vous pouvez augmenter la probabilité de trouver des résultats pertinents grâce aux fonctionnalités avancées de Spanner qui permettent d'élargir les requêtes de recherche avec des termes associés, des synonymes et des corrections orthographiques. Ces fonctionnalités incluent les éléments suivants :
Pour en savoir plus, consultez la section Recherche avec amélioration des requêtes.
Exigences concernant les requêtes SQL
Une requête SQL doit répondre à plusieurs conditions pour utiliser un index de recherche. Si ces conditions ne sont pas remplies, la requête utilise un plan de requête alternatif ou échoue si aucun plan alternatif n'existe.
Les requêtes doivent répondre aux conditions suivantes :
La fonction SEARCH et
SEARCH_SUBSTRINGnécessitent un index de recherche. Spanner ne prend pas en charge ces fonctions dans les requêtes sur la table de base ni dans les index secondaires.Les index partitionnés doivent avoir toutes les colonnes de partition liées par une condition d'égalité dans la
WHEREclause de la requête.Par exemple, si un index de recherche est défini comme
PARTITION BY x, y, la requête doit avoir 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 parSEARCHetSEARCH_SUBSTRINGopérateurs doivent être indexées dans le même index de recherche.Prenons l'exemple de 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 la section Ordre de tri des index de recherche.
Si l'index de recherche est filtré par 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 la section 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 la section Lire des données obsolètes. Cela est particulièrement utile pour les requêtes de recherche qui s'étendent sur de nombreuses divisions 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 elle contient l'une des fonctions de recherche. Ce comportement peut être remplacé par l'indicateur au niveau de l'instruction GoogleSQL @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} (mais les requêtes sont toujours sujettes à des conflits de verrouillage).
Une fois les conditions d'éligibilité de 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 en tant que littéral ou 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 d'index
Spanner sélectionne généralement l'index le plus efficace pour une requête à l'aide d'une modélisation basée sur les coûts. Toutefois, l'indicateur FORCE_INDEX indique explicitement à Spanner d'utiliser un index de recherche spécifique. Par exemple, voici 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 qui donne aux utilisateurs une idée du contenu d'un résultat de recherche et de la raison pour laquelle le résultat est pertinent pour leur requête.
Par exemple, Gmail utilise des extraits pour indiquer la partie d'un e-mail qui correspond à la requête de recherche :

La génération d'un extrait par la base de données présente plusieurs avantages :
- Praticité : vous n'avez pas besoin d'implémenter une 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 SNIPPET
fonction 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 surbrillance. 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, le code suivant 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')
Étape suivante
- 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.