Tokenisation

Cette page explique comment ajouter la tokenisation aux tables. La tokenisation est nécessaire pour créer les jetons utilisés dans l'index de recherche.

La tokenisation est le processus de transformation des valeurs en jetons. La méthode que vous utilisez pour tokeniser un document détermine les types et l'efficacité des recherches que les utilisateurs peuvent effectuer sur celui-ci.

Spanner fournit des tokenizers pour le texte en langage naturel, les sous-chaînes, le texte verbatim, les nombres et les valeurs booléennes. Le schéma de base de données utilise le tokenizer qui correspond au type de recherche nécessaire pour la colonne. Les tokenizers présentent les caractéristiques suivantes :

  • Chaque jetoniseur est une fonction SQL qui reçoit une entrée, telle qu'une chaîne ou un nombre, et des arguments nommés pour des options supplémentaires.
  • Le tokenizer génère un TOKENLIST.

Par exemple, une chaîne de texte The quick brown fox jumps over the lazy dog est tokenisée en [the,quick,brown,fox,jumps,over,the,lazy,dog]. Une chaîne HTML The <b>apple</b> is <i>red</i> est tokenisée en [the,apple,is,red].

Les jetons présentent les caractéristiques suivantes :

  • Les jetons sont stockés dans des colonnes qui utilisent le type de données TOKENLIST.
  • Chaque jeton est stocké sous forme de séquence d'octets, avec un ensemble facultatif d'attributs associés. Par exemple, dans les applications en texte intégral, un jeton est généralement un mot unique provenant d'un document textuel.
  • Lors de la tokenisation des valeurs HTML, Spanner génère des attributs qui indiquent la proéminence d'un jeton dans le document. Spanner utilise ces attributs pour la notation afin de mettre en avant les termes les plus importants (comme un titre).

Tokenizers

Spanner accepte les fonctions de tokenisation suivantes :

  • Le tokeniseur de texte intégral (TOKENIZE_FULLTEXT) produit des jetons de mots entiers pour les requêtes en langage naturel.

    Exemple

    Les deux fonctions suivantes

    GoogleSQL

    TOKENIZE_FULLTEXT("Yellow apple")
    TOKENIZE_FULLTEXT("Yellow <b>apple</b>", content_type=>"text/html")
    

    PostgreSQL

    Cet exemple utilise spanner.tokenize_fulltext.

    spanner.tokenize_fulltext("Yellow apple")
    spanner.tokenize_fulltext('Yellow <b>apple</b>', context_type=>'text/html')
    

    produisent les mêmes jetons : [yellow,apple].

  • Le tokeniseur de sous-chaînes (TOKENIZE_SUBSTRING) génère des jetons pour chaque n-gramme de chaque mot. Elle permet de trouver des sous-chaînes de mots dans un texte.

    Exemple

    GoogleSQL

    TOKENIZE_SUBSTRING('hello world', ngram_size_min=>4, ngram_size_max=>6)
    

    PostgreSQL

    Cet exemple utilise spanner.tokenize_substring.

    spanner.tokenize_substring('hello world', ngram_size_min=>4, ngram_size_max=>6)
    

    Génère les jetons suivants : [ello,hell,hello,orld,worl,world].

  • Le tokeniseur de n-grammes (TOKENIZE_NGRAMS) génère des n-grammes à partir d'une entrée (sans la diviser en mots distincts). Il permet d'accélérer les prédicats d'expression régulière.

    Exemple

    La fonction suivante :

    GoogleSQL

    TOKENIZE_NGRAMS("Big Time", ngram_size_min=>4, ngram_size_max=>4)
    

    PostgreSQL

    Cet exemple utilise spanner.tokenize_ngrams.

    spanner.tokenize_ngrams('big time', ngram_size_min=>4, ngram_size_max=>4)
    

    Génère les jetons suivants : ["Big ","ig T","g Ti"," Tim", "Time"].

  • Les tokenizers de correspondance exacte (TOKEN et TOKENIZE_BOOL) permettent de rechercher les lignes contenant une certaine valeur dans l'une de leurs colonnes. Par exemple, une application qui indexe un catalogue de produits peut vouloir rechercher des produits d'une marque et d'une couleur spécifiques.

    Exemples

    Les fonctions suivantes :

    GoogleSQL

    TOKEN("hello")
    TOKEN(["hello", "world"])
    

    PostgreSQL

    Cet exemple utilise spanner.token.

    spanner.token('hello')
    

    Génère les jetons suivants : [hello].

    La fonction suivante :

    GoogleSQL

    TOKENIZE_BOOL(true)
    

    PostgreSQL

    Cet exemple utilise spanner.tokenize_bool.

    spanner.tokenize_bool(true)
    

    Génère le jeton suivant : [y].

  • Les tokenizers numériques (TOKENIZE_NUMBER) permettent de générer un ensemble de jetons qui accélèrent les recherches de comparaison numérique. Pour les conditions d'égalité, le jeton est le nombre lui-même. Pour les conditions de plage (comme rating >= 3.5), l'ensemble de jetons est plus élaboré.

    Exemples

    Les instructions de fonction suivantes :

    GoogleSQL

    TOKENIZE_NUMBER(42, comparison_type=>'equality')
    TOKENIZE_NUMBER(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)
    

    PostgreSQL

    Cet exemple utilise spanner.tokenize_number.

    spanner.tokenize_number(42, comparison_type=>'equality')
    spanner.tokenize_number(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)
    

    Générez les jetons suivants, respectivement : "==42" et "==42", "[1,75]","[36, 45]","[36,55]","[36, 75]".

  • Les tokenizers JSON et JSONB (TOKENIZE_JSON et TOKENIZE_JSONB) permettent de générer un ensemble de jetons qui accélèrent les prédicats de présence de clé et de contenu JSON, tels que doc[@key] IS NOT NULL (GoogleSQL) ou doc ? 'key' (PostgreSQL).

Les fonctions de tokenisation sont généralement utilisées dans une expression de colonne générée. Ces colonnes sont définies comme HIDDEN afin de ne pas être incluses dans les résultats des requêtes SELECT *.

L'exemple suivant utilise un tokenizer de texte intégral et un tokenizer numérique pour créer une base de données qui stocke les noms et les notes des albums de musique. L'instruction LDD a deux fonctions :

  1. Définit les colonnes de données AlbumTitle et Rating.
  2. Définit AlbumTitle_Tokens et AlbumRating_Tokens. Ces colonnes TOKENLIST tokenisent les valeurs des colonnes de données afin que Spanner puisse les indexer.

    GoogleSQL

    CREATE TABLE Albums (
      AlbumId STRING(MAX) 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);
    

    PostgreSQL

    CREATE TABLE albums (
      albumid character varying NOT NULL,
      albumtitle character varying,
      albumtitle_Tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
    PRIMARY KEY(albumid));
    

Chaque fois que les valeurs de base sont modifiées, AlbumTitle_Tokens et Rating_Tokens sont automatiquement mises à jour.

Tokeniser du contenu en texte brut ou HTML

La tokenisation du texte est compatible avec les types de contenu texte brut et HTML. Utilisez la fonction Spanner TOKENIZE_FULLTEXT pour créer des jetons. Utilisez ensuite l'instruction LDD CREATE SEARCH INDEX pour générer l'index de recherche.

Par exemple, l'instruction LDD CREATE TABLE suivante utilise la fonction TOKENIZE_FULLTEXT pour créer des jetons à partir de AlbumTitles dans la table Albums. L'instruction LDD CREATE SEARCH INDEX crée un index de recherche avec le nouveau AlbumTitles_Tokens.

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(AlbumTitle_Tokens)

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  albumtitle character varying,
  albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(albumtitle_tokens)

Le processus de tokenisation utilise les règles suivantes :

  • La tokenisation n'inclut pas la racinisation ni la correction des mots mal orthographiés. Par exemple, dans une phrase comme "Un chat regardait un groupe de chats", le jeton "chat" est indexé séparément du jeton "chats". Contrairement à d'autres moteurs de recherche qui normalisent les jetons lors des écritures, Spanner offre la possibilité d'étendre la requête de recherche pour inclure différentes formes de mots. Pour en savoir plus, consultez Mode requête amélioré.
  • Les mots vides (comme "un") sont inclus dans l'index de recherche.
  • La recherche en texte intégral n'est jamais sensible à la casse. Le processus de tokenisation convertit tous les jetons en minuscules.

Le processus de tokenisation suit les positions de chaque jeton dans le texte d'origine. Ces positions sont ensuite utilisées pour faire correspondre les expressions. Les positions sont stockées dans l'index de recherche, à côté des docid.

Google continue d'améliorer les algorithmes de tokenisation. Dans certains cas, cela peut entraîner une tokenisation différente d'une chaîne à l'avenir par rapport à la façon dont elle est tokenisée actuellement. Nous espérons que ce genre de situation ne se présentera que rarement. Par exemple, si la segmentation des langues chinoise, japonaise et coréenne (CJK) est améliorée.

L'argument content_type indique si le format du contenu utilise du texte brut ou HTML. Utilisez les paramètres suivants pour définir content_type :

  • Pour la tokenisation du texte, définissez l'argument content_type sur "text/plain". Il s'agit du paramètre par défaut.
  • Pour la tokenisation HTML, définissez l'argument content_type sur "text/html. Sans cet argument, les balises HTML sont traitées comme des signes de ponctuation. En mode HTML, Spanner utilise des heuristiques pour déduire l'importance du texte sur la page. Par exemple, si le texte se trouve dans un titre ou sa taille de police. Les attributs HTML acceptés incluent small, medium, large, title et "link". Comme la position, l'attribut est stocké à côté du jeton dans l'index de recherche. La tokenisation ne crée pas de jetons pour les balises HTML.

Les attributs de jeton n'ont pas d'incidence sur la correspondance ni sur les résultats des fonctions SEARCH ou SEARCH_SUBSTRING. Elles ne sont utilisées que pour le classement.

L'exemple suivant montre comment tokeniser du texte :

GoogleSQL

CREATE TABLE T (
  ...
  Text STRING(MAX),
  Html STRING(MAX),
  Text_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Text, content_type=>"text/plain")) HIDDEN,
  Html_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Html, content_type=>"text/html")) HIDDEN
) PRIMARY KEY(...);

PostgreSQL

CREATE TABLE t (
  ...
  text character varying,
  html character varying,
  text_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(text, content_type=>"text/plain")) VIRTUAL HIDDEN,
  html_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(html, content_type=>'type/html')) VIRTUAL HIDDEN,
PRIMARY KEY(...));

Affinement de la détection de la langue avec l'argument language_tag

Par défaut, la tokenisation détecte automatiquement la langue d'entrée. Lorsque la langue d'entrée est connue, un argument language_tag peut être utilisé pour affiner ce comportement :

GoogleSQL

AlbumTitle_Tokens TOKENLIST
  AS (TOKENIZE_FULLTEXT(AlbumTitle, language_tag=>"en-us")) HIDDEN

PostgreSQL

albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle, language_tag=>'en-us')) VIRTUAL HIDDEN

La plupart des applications ne spécifient pas l'argument language_tag et s'appuient plutôt sur la détection automatique de la langue. La segmentation pour les langues asiatiques comme le chinois, le coréen et le japonais ne nécessite pas de définir la langue de tokenisation.

Les exemples suivants montrent des cas où language_tag affecte la tokenisation :

Fonction de tokénisation Jetons produits
TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que") [a, tout, pourquoi, il, ya, un, parce, que]
TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que", \ language_tag=>"fr") [a, tout, pourquoi, il, y, a, un, parce, que]
TOKENIZE_FULLTEXT("旅 行") Deux jetons : [旅, 行]
TOKENIZE_FULLTEXT("旅 行", language_tag=>"zh") Un jeton : [旅行]

Étapes suivantes