Combinare TOKENLIST

Questa pagina descrive come concatenare TOKENLIST in un indice di ricerca quando configuri lo schema o in una query di ricerca quando esegui una ricerca full-text in Spanner.

Combinare TOKENLIST in un indice di ricerca

A volte, devi fare in modo che la tua applicazione esegua ricerche in singoli campi. In altri casi, l'applicazione deve eseguire la ricerca in tutti i campi. Ad esempio, in una tabella con due colonne di stringhe, potresti voler che la tua applicazione esegua ricerche in entrambe le colonne senza distinguere da quale colonna provengono le corrispondenze.

In Spanner, esistono due modi per farlo:

  1. Tokenizza le parole separatamente e concatena gli TOKENLIST risultanti (opzione consigliata).
  2. Concatenare le stringhe e tokenizzare il risultato.

Con il secondo approccio, ci sono due problemi:

  1. Se vuoi indicizzare Title o Studio singolarmente, oltre a indicizzarli in un TOKENLIST combinato, lo stesso testo viene tokenizzato due volte. Ciò fa sì che le transazioni utilizzino più risorse.
  2. La ricerca di una frase si estende a entrambi i campi. Ad esempio, se @p è impostato su "Blue Note", corrisponde a una riga che contiene sia Title="Big Blue Note" sia Studio="Blue Note Studios".

Il primo approccio risolve questi problemi perché una frase corrisponde a un solo campo e ogni campo stringa viene tokenizzato una sola volta se vengono indicizzati sia i TOKENLIST singoli che quelli combinati. Anche se ogni campo stringa viene tokenizzato una sola volta, i TOKENLIST risultanti vengono memorizzati separatamente nell'indice.

Tokenizza le parole separatamente e concatenale TOKENLIST

Il seguente esempio tokenizza ogni parola e utilizza TOKENLIST_CONCAT per concatenare i TOKENLIST:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
  Combined_Tokens TOKENLIST AS (TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens])) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);

SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);

PostgreSQL

PostgreSQL utilizza spanner.tokenlist_concat per la concatenazione. Il parametro di ricerca $1 è associato a "Hatel Kaliphorn".

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
  combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenlist_concat(ARRAY[spanner.tokenize_fulltext(title), spanner.tokenize_fulltext(studio)])) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);

SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);

Tieni presente che tokenlist_concat non chiama title_tokens o studio_tokens, ma chiama spanner.tokenize_fulltext(title) e spanner.tokenize_fulltext(studio). Questo perché PostgreSQL non supporta i riferimenti alle colonne generate che si trovano all'interno di altre colonne generate. spanner.tokenlist_concatdeve chiamare le funzioni di tokenizzazione e non fare riferimento direttamente alle colonne tokenlist.

La concatenazione di TOKENLIST può essere implementata anche interamente sul lato della query. Per maggiori informazioni, consulta la sezione Concatenazione TOKENLIST lato query.

TOKENLIST_CONCAT è supportato sia per la ricerca a testo intero sia per la ricerca di sottostringhe. Spanner non consente di combinare tipi di tokenizzazione, ad esempio TOKENIZE_FULLTEXT e TOKENIZE_SUBSTRING nella stessa chiamata TOKENLIST_CONCAT.

In GoogleSQL, la definizione delle colonne di testo TOKENLIST può essere modificata nelle colonne non archiviate per aggiungere colonne aggiuntive. Questa opzione è utile quando vuoi aggiungere una colonna aggiuntiva a TOKENLIST_CONCAT. La modifica dell'espressione della colonna generata non esegue il backfill delle righe esistenti nell'indice.

Concatenare stringhe e tokenizzare il risultato

L'esempio seguente concatena le stringhe e tokenizza il risultato:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Combined_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title || " " || Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);

SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title || ' ' || studio)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);

SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);

Concatenazione TOKENLIST lato query

Il compromesso con l'indicizzazione di TOKENLIST concatenati è che aumenta i costi di archiviazione e scrittura. Ora ogni token viene memorizzato due volte sul disco: una volta in un elenco di pubblicazione del suo TOKENLIST originale e una volta in un elenco di pubblicazione del TOKENLIST combinato. La concatenazione lato query delle colonne TOKENLIST evita questo costo, ma la query utilizza più risorse di calcolo.

Per concatenare più TOKENLIST, utilizza la funzione TOKENLIST_CONCAT nella query SEARCH. Per questa sezione, utilizziamo il seguente schema di esempio:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Title_Tokens, Studio_Tokens);

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
 PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(title_tokens, studio_tokens);

La seguente query cerca le righe che contengono i token "blue" e "note" in qualsiasi punto delle colonne Title e Studio. Sono incluse le righe con "blue" e "note" nella colonna Title, "blue" e "note" nella colonna Studio e "blue" nella colonna Title e "note" nella colonna Studio o viceversa.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([AlbumTitle_Tokens, Studio_Tokens]), 'blue note')

PostgreSQL

Questo esempio utilizza spanner.search con spanner.tokenlist_concat.

SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[albumtitle_tokens, studio_tokens]), 'blue note')

La concatenazione lato scrittura e lato query TOKENLIST produce risultati identici. La scelta tra i due è un compromesso tra il costo del disco e il costo delle query.

In alternativa, un'applicazione potrebbe cercare più colonne TOKENLIST e utilizzare OR insieme alla funzione SEARCH:

GoogleSQL

SEARCH(AlbumTitle_Tokens, 'Blue Note') OR SEARCH(Studio_Tokens, 'Blue Note')

PostgreSQL

spanner.search(albumtitle_tokens, 'Blue Note') OR spanner.search(studio_tokens, 'Blue Note')

Tuttavia, ha una semantica diversa. Non corrisponde agli album in cui AlbumTitle_Tokens contiene "blue", ma non "note" e Studio_Tokens contiene "note", ma non "blue".

Passaggi successivi