Los ejemplos de la sección anterior ilustraron la coincidencia de texto completo utilizando cadenas constantes simples. Esta sección muestra cómo buscar datos de tablas, opcionalmente utilizando índices.
Es posible hacer una búsqueda en texto completo sin un índice. Una consulta simple
para imprimir el title of each row that contains the word
friend in its body field is:
SELECT title
FROM pgweb
WHERE to_tsvector('english', body) @@ to_tsquery('english', 'friend');
Esto también encontrará palabras relacionadas como friends
y friendly, ya que todas ellas se reducen al mismo
lexema normalizado.
La consulta anterior especifica que se debe usar la configuración english
para analizar y normalizar las cadenas. Alternativamente,
podríamos omitir los parámetros de configuración:
SELECT title
FROM pgweb
WHERE to_tsvector(body) @@ to_tsquery('friend');
Esta consulta utilizará la configuración establecida por default_text_search_config.
Un ejemplo más complejo es
seleccionar los diez documentos más recientes que contienen create y
table en el title o en el body:
SELECT title
FROM pgweb
WHERE to_tsvector(title || ' ' || body) @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;
Para mayor claridad, hemos omitido las llamadas a la función coalesce
que serían necesarias para encontrar filas que contengan NULL
en uno de los dos campos.
Aunque estas consultas funcionarán sin un índice, la mayoría de las aplicaciones encontrarán este enfoque demasiado lento, excepto quizás para búsquedas ad-hoc ocasionales. El uso práctico de la búsqueda de texto generalmente requiere crear un índice.
Podemos crear un índice GIN (Section 12.9) para acelerar las búsquedas de texto:
CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', body));
Observa que se utiliza la versión de 2 argumentos de to_tsvector.
Solo las funciones de búsqueda de texto que especifican un nombre de configuración se pueden
usar en índices de expresiones (Section 11.7).
Esto se debe a que el contenido del índice no debe verse afectado por default_text_search_config. Si se vieran afectados, el
contenido del índice podría ser inconsistente porque diferentes entradas podrían
contener tsvectors creados con diferentes configuraciones de búsqueda de texto,
y no habría forma de adivinar cuál es cuál. Sería
imposible volcar y restaurar dicho índice correctamente.
Debido a que en el índice anterior se utilizó la versión de dos argumentos de to_tsvector,
solo una referencia de consulta que use la versión de 2 argumentos
de to_tsvector con el mismo nombre de configuración
utilizará ese índice. Es decir, WHERE
to_tsvector('english', body) @@ 'a & b' puede usar el índice,
but WHERE to_tsvector(body) @@ 'a & b' cannot.
This ensures that an index will be used only with the same configuration
used to create the index entries.
Es posible configurar índices de expresiones más complejos en los que el nombre de la configuración se especifique mediante otra columna, por ejemplo:
CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector(config_name, body));
donde config_name es una columna en la tabla pgweb.
Esto permite configuraciones mixtas en el mismo índice mientras se
registra qué configuración se utilizó para cada entrada del índice. Esto
sería útil, por ejemplo, si la colección de documentos contuviera
documentos en diferentes idiomas. Nuevamente,
las consultas que están destinadas a usar el índice deben estar redactadas de manera que coincidan, por ejemplo,
WHERE to_tsvector(config_name, body) @@ 'a & b'.
Los índices pueden incluso concatenar columnas:
CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', title || ' ' || body));
Otro enfoque consiste en crear una columna tsvector separada
para contener la salida de to_tsvector. Para mantener esta
columna automáticamente actualizada con sus datos de origen, usa una columna generada almacenada.
Este ejemplo es una
concatenación de title y body,
utilizando coalesce para asegurar que un campo se siga
indexando cuando el otro sea NULL:
ALTER TABLE pgweb
ADD COLUMN textsearchable_index_col tsvector
GENERATED ALWAYS AS (to_tsvector('english', coalesce(title, '') || ' ' || coalesce(body, ''))) STORED;
Luego creamos un índice GIN para acelerar la búsqueda:
CREATE INDEX textsearch_idx ON pgweb USING GIN (textsearchable_index_col);
Ahora estamos listos para realizar una búsqueda rápida en texto completo:
SELECT title
FROM pgweb
WHERE textsearchable_index_col @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;
Una ventaja del enfoque de columna separada sobre un índice de expresión
es que no es necesario especificar explícitamente la configuración de búsqueda de
texto en las consultas para poder utilizar el índice. Como se muestra
en el ejemplo anterior, la consulta puede depender de
default_text_search_config. Otra ventaja es que
las búsquedas serán más rápidas, ya que no será necesario volver a realizar las
llamadas a to_tsvector para verificar las coincidencias del índice. (Esto es más
importante cuando se utiliza un índice GiST que uno GIN; consulta la Section 12.9). Sin embargo, el enfoque de índice de expresión es
más fácil de configurar y requiere menos espacio en disco, ya que la
representación tsvector no se almacena explícitamente.