En esta página se describe cómo concatenar TOKENLIST
s en un índice de búsqueda al configurar el esquema o en una consulta de búsqueda al realizar una búsqueda de texto completo en Spanner.
Combinar TOKENLISTs en un índice de búsqueda
En ocasiones, necesitas que tu aplicación busque en campos concretos. En otras ocasiones, la aplicación necesita buscar en todos los campos. Por ejemplo, en una tabla con dos columnas de cadena, puede que quieras que tu aplicación busque en ambas columnas sin diferenciar de qué columna proceden las coincidencias.
En Spanner, hay dos formas de hacerlo:
- Tokeniza las palabras por separado y concatena los
TOKENLIST
s resultantes (opción recomendada). - Concatenar cadenas y tokenizar el resultado.
Con el segundo enfoque, hay dos problemas:
- Si quiere indexar
Title
oStudio
por separado, además de indexarlos en unTOKENLIST
combinado, el mismo texto se tokeniza dos veces. Esto hace que las transacciones usen más recursos. - Una búsqueda de frase abarca ambos campos. Por ejemplo, si
@p
se define como"Blue Note"
, se corresponde con una fila que contiene tantoTitle
="Big Blue Note" comoStudio
="Blue Note Studios".
El primer enfoque resuelve estos problemas porque una frase solo coincide con un campo y cada campo de cadena solo se tokeniza una vez si se indexan tanto los términos individuales como los combinados.TOKENLIST
Aunque cada campo de cadena solo se tokeniza una vez, los TOKENLIST
resultantes se almacenan por separado en el índice.
Tokeniza las palabras por separado y concatena los TOKENLIST
s
En el siguiente ejemplo se tokeniza cada palabra y se usa TOKENLIST_CONCAT
para concatenar los TOKENLIST
s:
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 usa
spanner.tokenlist_concat
para la concatenación. El parámetro de consulta $1
está vinculado 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);
Ten en cuenta que tokenlist_concat
no llama a title_tokens
ni a studio_tokens
, sino a spanner.tokenize_fulltext(title)
y spanner.tokenize_fulltext(studio)
. Esto se debe a que PostgreSQL no admite referencias a columnas generadas que estén dentro de otras columnas generadas. spanner.tokenlist_concat
debe llamar a las funciones de tokenización y no hacer referencia a las columnas de la lista de tokens directamente.
La concatenación TOKENLIST
también se puede implementar por completo en el lado de la consulta.
Para obtener más información, consulta Concatenación TOKENLIST
del lado de la consulta.
TOKENLIST_CONCAT
se admite tanto en búsquedas de texto completo como de subcadenas.
Spanner no permite mezclar tipos de tokenización, como TOKENIZE_FULLTEXT
y TOKENIZE_SUBSTRING
, en la misma llamada TOKENLIST_CONCAT
.
En GoogleSQL, la definición de las columnas de texto TOKENLIST
se puede cambiar en columnas no almacenadas para añadir columnas adicionales. Esto resulta útil cuando quieres añadir una columna adicional a TOKENLIST_CONCAT
. Si cambia la expresión de la columna generada, no se rellenarán las filas del índice.
Concatenar cadenas y tokenizar el resultado
En el siguiente ejemplo se concatenan cadenas y se tokeniza el resultado:
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);
Concatenación TOKENLIST
del lado de la consulta
La desventaja de indexar el TOKENLIST
concatenado es que aumenta el coste de almacenamiento y escritura. Ahora, cada token se almacena en el disco dos veces: una en una lista de publicaciones de su TOKENLIST
original y otra en una lista de publicaciones del TOKENLIST
combinado. La concatenación del lado de la consulta de TOKENLIST
columnas evita este coste, pero la consulta usa más recursos de computación.
Para concatenar varios TOKENLIST
s, usa la función TOKENLIST_CONCAT
en la consulta SEARCH
. En esta sección, usaremos el siguiente esquema de ejemplo:
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 siguiente consulta busca filas que tengan los tokens "blue" y "note" en cualquier parte de las columnas Title
y Studio
. Esto incluye las filas que contienen tanto "azul" como "nota" en la columna Title
, "azul" y "nota" en la columna Studio
, y "azul" en la columna Title
y "nota" en la columna Studio
, o viceversa.
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([AlbumTitle_Tokens, Studio_Tokens]), 'blue note')
PostgreSQL
En este ejemplo se usa
spanner.search
con
spanner.tokenlist_concat
.
SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[albumtitle_tokens, studio_tokens]), 'blue note')
La concatenación del lado de escritura y del lado de consulta TOKENLIST
produce resultados idénticos.
La elección entre ambos supone un equilibrio entre el coste del disco y el coste de las consultas.
También puede buscar en varias columnas TOKENLIST
y usar OR
junto con la función 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')
Sin embargo, tiene una semántica diferente. No coincide con los álbumes en los que AlbumTitle_Tokens
tiene "azul", pero no "nota", y Studio_Tokens
tiene "nota", pero no "azul".
Siguientes pasos
- Consulta información sobre las consultas de búsqueda de texto completo.
- Consulta información sobre los índices de búsqueda.