Full text search engine
Desarrollo
Si de por si desde hace años PostgreSQL es una base de datos superior a MySQL, pero con las nuevas características de la versión 8.3 hay todavía más razones para profundizar en esta hermana pequeña de Oracle.
Una de las cosas más esperadas es el Full Text Search Engine (FTSE), que es con lo que estoy jugando. Aún no lo entiendo del todo pero al parecer la cosa está asi, existen dos funciones to_tsvector() y to_tsquery() que convierten los datos de la tabla en "lexemas" de búsqueda, sólo los lexemas válidos entran el FTSE.
Primero hay que inicializar un diccionario para nuestro idioma dentro de psql de nuestra DB:
CREATE TEXT SEARCH DICTIONARY karamelo_es (
template = snowball,
language = spanish,
stopwords = spanish
);
CREATE TEXT SEARCH CONFIGURATION public.karamelo_es ( COPY = pg_catalog.spanish );
Sin esto el buscador no encuentra cosas en español pues los lexemas no están dados de alta. Ahora ya podemos buscar, por ejemplo tengo una tabla "news" con los campos id, title, body y created y voy a buscar todos los rows donde aparezca el término "Educación" en el campo body:
SELECT news.id, news.title FROM news WHERE to_tsvector('karamelo_es', body) @@ to_tsquery('karamelo_es','Educación') ORDER BY created DESC LIMIT 20;
Lo mejor es crear un índice de lexemas castellanos en esta tabla para acelerar la búsqueda:
CREATE INDEX pgnews_idx ON news USING gin(to_tsvector('karamelo_es', body));
Pero eso no es todo, con la nueva función ts_rank_cd de PostgreSQL 8.3 puedo hacer un ranking automático para que las noticias donde más aparece el término se listen primero:
SELECT id, title, ts_rank_cd(to_tsvector('karamelo_es', body), to_tsquery('karamelo_es','Educación | sexualidad')) AS rank FROM news, to_tsquery('karamelo_es','Educación | sexualidad') query WHERE to_tsquery('karamelo_es','Educación | sexualidad') @@ to_tsvector('karamelo_es', body) ORDER BY rank DESC LIMIT 20;
que me regresa los rows:
id | title | rank
----+------------------------------------------------------------------------------+------
8 | La educación sexual debe iniciar desde preescolar: UNESCO | 0.4
15 | SEP: sanción a quien use libro del GDF de educación sexual | 0.3
9 | Las cuotas escolares son necesarias: SEJ | 0.1
10 | Informa SEP estatus de planteles que perdieron registro | 0.1
11 | Ofrece Michoacán educación a distancia a inmigrantes en EU | 0.1
13 | Un rompecabezas, el sistema educativo nacional, diagnóstico de especialistas | 0.1
(6 rows)
En este último ejemplo estoy buscando dos términos "educación" y "sexualidad", sólo los separo con un pipe (|), obviamente en PHP el query se haría con variables que definirían los términos y el idioma de los términos. En el FTSE mayúsculas o minúsculas no importan.
Pero eso no es todo, postgresql puede resaltar las palabras en la búsqueda luego de encontrar los campos con la función ts_headline:
SELECT id, title, ts_headline('karamelo_es', body, to_tsquery('karamelo_es','Educación | sexualidad')), rank FROM ( SELECT id, title, substr(body,0,160) as body, ts_rank_cd(to_tsvector('karamelo_es', body), to_tsquery('karamelo_es','Educación | sexualidad')) AS rank FROM news, to_tsquery('karamelo_es','Educación | sexualidad') query WHERE to_tsquery('karamelo_es','Educación | sexualidad') @@ to_tsvector('karamelo_es', body) ORDER BY rank DESC LIMIT 20 ) AS foo;
De este modo al ver los resultados el usuario ve exactamente donde se encuentran los términos que buscó.
Por si esto fuera poco la velocidad de PostgreSQL 8.3 se incrementó perronamente:
Conclusión: PostgreSQL rulez!!
Permalink: http://www.mononeurona.org/users/entry/aarkerio/1588
Comentblogs:










