Saltar al contenido

Búsqueda de texto completo de PostgreSQL en muchas columnas

Solución:

Sugiero esta expresión para consulta e índice:

SELECT * FROM tbl
WHERE  to_tsvector('simple', f_concat_ws(' ', country, city, street, house_nr, postcode))
    @@ plainto_tsquery('simple', '22 Kärntner Wien');

Tenga en cuenta la función personalizada f_concat_ws() encima. Eso es porque concat_ws() es solo STABLE no IMMUTABLE. Necesitas crearlo primero:

CREATE OR REPLACE FUNCTION f_concat_ws(text, VARIADIC text[])
  RETURNS text LANGUAGE sql IMMUTABLE AS 'SELECT array_to_string($2, $1)';

Se puede utilizar como reemplazo directo de concat_ws(), excepto que solo acepta datos de texto reales como entrada (lo que nos permite hacer que IMMUTABLE sin hacer trampa, efectivamente). Explicación detallada (¡léelo!):

  • Combinar dos columnas y agregarlas en una nueva columna

Sobre VARIADIC:

  • Pasando varios valores en un solo parámetro

Para muchos columnas, esto es más corto y más rápido. usted podría prescindir de él, pero luego la sintaxis se vuelve bastante detallada (ver la respuesta de joanolo).

El índice coincidente para ir con esto:

CREATE INDEX tbl_adr_fts_idx ON tbl USING GIN (
       to_tsvector('simple', f_concat_ws(' ', country, city, street, house_nr, postcode)));

Está tratando con datos de direcciones internacionales, así que hágalo no utilizar el english configuración de búsqueda de texto. La derivación tiene poco sentido para nombres y la mayoría de los datos de su ejemplo ni siquiera son en inglés para empezar. Utilizar el simple configuración en su lugar. Necesita el formulario con dos parámetros; consulte a continuación.

Concatenar las cadenas y llamar a la función más cara to_tsvector() una vez. Usar concat_ws() para hacer frente a los posibles valores NULL con elegancia. Más barato en general y también más corto.

  • Reemplazo de cadenas usando cadenas concatenadas de varias columnas

Como comenté, la búsqueda de texto completo tiene soporte limitado para la concordancia aproximada, pero existe la característica de la concordancia de prefijos que a menudo se pasa por alto:

  • Obtenga una coincidencia parcial de la columna TSVECTOR indexada por GIN

Entonces, si no está seguro de si es ‘Kärntner’ o ‘Kärnten’y si es ‘Straße’, ‘strasse’ o ‘Strabe’ (como en sus datos de ejemplo con errores) pero sabe que la segunda palabra sigue a la primera, podría:

... @@ to_tsquery('simple', '22 & Kärnt:* <-> Stra:* & Wien')

<-> es el operador de búsqueda de frases y requiere Postgres 9,6.

  • ¿Cómo almacenar historias cortas para acceder a frases individuales?

Y si también quieres ignorar los signos diacríticos (‘a’ <> ‘a’), agregar unaccent() a la mezcla. Puedes usarlo como separado función o puedes agregarlo como diccionario a su configuración de búsqueda de texto. Primero debes instalar la extensión …

  • ¿PostgreSQL admite intercalaciones “insensibles al acento”?

Descripción general de la opción de coincidencia de patrones en instalaciones típicas de Postgres:

  • Coincidencia de patrones con LIKE, SIMILAR TO o expresiones regulares en PostgreSQL

Joanolo ya proporcionó información básica sobre FTS y el enlace al manual para obtener más información.

Abordar su comentario

Estoy intentando agregar este índice pero me da un error:

ERROR: functions in index expression must be marked IMMUTABLE

Hay dos variantes de la función to_tsvector() – ver “sobrecarga de funciones”. El primero toma solo text, la segunda toma regconfig y text. Ver por ti mismo:

SELECT proname, provolatile, proargtypes[0]::regtype, proargtypes[1]::regtype
FROM   pg_proc
WHERE  proname="to_tsvector";

Solo el segundo es IMMUTABLE y se puede utilizar directamente en una expresión de índice. ‘sencillo’ en el ejemplo anterior es una configuración de búsqueda de texto (regconfig).

Más importante, mi descuido: concat_ws() (que tenía en mi primera versión) es solo STABLE, no IMMUTABLE. Agregué los pasos necesarios arriba.

Relacionado:

  • ¿Cómo afectan las palabras clave INMUTABLE, STABLE y VOLATILE al comportamiento de la función?

  • Combinar dos columnas y agregarlas en una nueva columna

Imaginemos que esta es su tabla y algunos datos:

CREATE TABLE t
(
    country text,
    city text,
    street text,
    house_number text,
    post_code text
) ;

INSERT INTO t
VALUES
   ('Österreich', 'Vienna', 'HauptStrasse', '123', '12345'),   
   ('France', 'Paris', 'Rue du Midi', '12A', '01234'),   
   ('España', 'Barcelona', 'Passeig de Gràcia', '32', '08001'),   
   ('United Kingdom', 'London', 'Oxford Street', '20', 'W1D 1AS'),
   ('Nederland', 'Amsterdam', 'Leidsekruisstraat', '6-8', '1017 RH') ;

[NOTE: check it at http://rextester.com/DOJN8533]

La forma de realizar una búsqueda de texto completo en varias columnas usando PostgreSQL (asumiendo que ‘inglés’ es el nombre de su configuración de FTS), es usando una consulta como:

SELECT
    *
FROM
    t
WHERE
    (
        to_tsvector('english', coalesce(country, ''))      || 
        to_tsvector('english', coalesce(city, ''))         || 
        to_tsvector('english', coalesce(street, ''))       || 
        to_tsvector('english', coalesce(house_number, '')) ||
        to_tsvector('english', coalesce(post_code, '')) 
    ) @@ plainto_tsquery('english', 'Amsterdam') ;

Donde clasuse significa:

 (this tsvector = document) @@ /* matches */  (this tsquery = query)

A tsvector es un tipo de datos especial utilizado por PostgreSQL para almacenar datos transformados (por ejemplo, todos en minúsculas, con comas eliminadas, con palabras identificadas y enumeradas, etc.) sobre un texto. A tsquery es una forma de pregunta por características de un documento (por ejemplo que contiene esto _y_ eso).

los || operador combina tsvectors (digamos que “los suma”).

Si desea acelerar las cosas, debe tener un índice funcional, definido como:

CREATE INDEX ts_idx 
    ON t USING gist ( 
    (
        to_tsvector('english', coalesce(country, '')) || 
        to_tsvector('english', coalesce(city, '')) || 
        to_tsvector('english', coalesce(street, '')) || 
        to_tsvector('english', coalesce(house_number, '')) ||
        to_tsvector('english', coalesce(post_code, ''))
    ) 
) ;

Debe comprobar detenidamente la documentación sobre la búsqueda de texto completo. Es un poco intimidante, porque hay muchas posibilidades, pero vale la pena dedicarle tiempo.

Para ordenar los resultados cuando hay muchos, debe usar él ts_rank función para ORDER BY y luego limitar.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *