2011-05-27 4 views
6

Estoy buscando una forma de emular algo como SELECT * FROM table WHERE attr LIKE '%text%' usando un tsvector en PostgreSQL.Coincidir con una frase que termina en un prefijo con búsqueda de texto completo

He creado un atributo tsvector sin utilizar un diccionario. Ahora, una consulta como ...

SELECT title 
FROM table 
WHERE title_tsv @@ plainto_tsquery('ph:*'); 

... volverían todos los títulos como 'Física', 'PHP', etc, pero ¿cómo puedo crear una consulta que devuelve todos los registros en los que el título comienza con ' Zend Fram '(¿cuál debería devolver, por ejemplo,' Zend Framework ')?

Por supuesto, podría usar algo como:

SELECT title 
FROM table 
WHERE title_tsv @@ to_tsquery('zend') 
AND title_tsv @@ to_tsquery('fram:*'); 

Sin embargo, esto parece un poco incómodo.

Entonces, la pregunta es: ¿hay una manera de formular la consulta dada anteriormente usando algo como:

SELECT title 
FROM table 
WHERE title_tsv @@ to_tsquery('zend fram:*'); 

Respuesta

5
SELECT title 
FROM table 
WHERE title_tsv @@ to_tsquery('zend') and 
title_tsv @@ to_tsquery('fram:*') 

es equivalente a:

SELECT title 
FROM table 
WHERE title_tsv @@ to_tsquery('zend & fram:*') 

pero por supuesto que encuentra "Zend no tiene marco" también.

Por supuesto, puede expresar una coincidencia de expresión regular con el título después de la coincidencia de tsquery, pero tendría que usar explicar analizar para asegurarse de que se estaba ejecutando después de la cita en lugar de antes.

2

Hay una manera de hacerlo en Postgres usando trigrams y los índices Gin/Gist. Hay un ejemplo simple, pero con algunas asperezas, en este artículo de Kristo Kaiv: Substring Search.

1
No

una solución bastante, pero debe hacer el trabajo:

psql=# SELECT regexp_replace(cast(plainto_tsquery('Zend Fram') as text), E'(\'\\w+\')', E'\\1:*', 'g') ; 
    regexp_replace  
--------------------- 
'zend':* & 'fram':* 
(1 row) 

Puede ser utilizado como:

psql=# SELECT title FROM table WHERE title_tsv(title) @@ to_tsquery(regexp_replace(cast(plainto_tsquery('Zend Fram') as text), E'(\'\\w+\')', E'\\1:*', 'g')); 

¿Cómo funciona esto:

  1. arroja el tsquery llanura a una cadena: cast(plainto_tsquery('Zend Fram') as text)
  2. usa expresiones regulares para anexar :* prefix matcher para cada término de búsqueda: regexp_replace(..., E'(\'\\w+\')', E'\\1:*', 'g')
  3. lo convierte de nuevo en un tsquery no claro. to_tsquery(...)
  4. y lo utiliza en la expresión de búsqueda SELECT title FROM table WHERE title_tsv(title) @@ ...
2

Postgres 9.6 introduce capacidades de búsqueda de frase para la búsqueda de texto completo.Por lo que este funciona ahora:

SELECT title 
FROM tbl 
WHERE title_tsv @@ to_tsquery('zend <-> fram:*');

<-> being the FOLLOWED BY operator.

Se encuentra 'foo Zend barra de marco' o 'Zend marcos', pero no'foo Zend tiene ninguna barra de marco'.

Citando la consulta release notes for Postgres 9.6:

Una frase de búsqueda de se puede especificar en tsquery de entrada con los nuevos operadores <-> y <N>. El primero significa que los lexemas anteriores y después deben aparecer adyacentes entre sí en ese orden. El último significa que deben ser exactamente N lexemas aparte.

Para un mejor apoyo al rendimiento de la consulta con un índice de GIN:

CREATE INDEX tbl_title_tsv_idx ON tbl USING GIN (title_tsv); 

O no almacene title_tsv en la tabla en absoluto (hinchazón y complican escrituras). Se puede usar un índice de expresión en lugar:

CREATE INDEX tbl_title_tsv_idx ON tbl USING GIN (to_tsvector('english', title)); 

Es necesario especificar la configuración de búsqueda de texto (a menudo un lenguaje específico) para hacer que la expresión inmutable. Y adaptar la consulta en consecuencia:

... 
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'zend <-> fram:*'); 
Cuestiones relacionadas