[Linuxtrent] Re: Postgresql - ricerca full text

  • From: Stefano Morandi <liste@xxxxxxxxxxxx>
  • To: linuxtrent@xxxxxxxxxxxxx
  • Date: Wed, 3 Dec 2008 12:02:16 +0100


Il giorno 03/dic/08, alle ore 06:55, Guido Brugnara ha scritto:

> Se devi fare delle query semplici, Postgresql implementa l'operatore
> "~*" con il quale puoi fare confronti usando la sintassi delle
> espressioni regolari.

Rispondo a Guido per semplicità, ma grazie a tutti per le risposte.
Al solito mi sono spiegato malissimo :-( Provo con un esempio perché la
cosa magari interessa anche altri (mi sa di no, ma fa lo stesso :-) )


CREATE TABLE prova
(
  idchiave integer NOT NULL,
  testo text,
  testo_fts tsvector,
CONSTRAINT prova_pkey PRIMARY KEY (idchiave) USING INDEX TABLESPACE tblindex
)
WITH (OIDS=FALSE);

-- Alcuni dati di prova
INSERT INTO prova (idchiave, testo, testo_fts) VALUES (1, 'Sistema Operativo', NULL); INSERT INTO prova (idchiave, testo, testo_fts) VALUES (2, 'Operazione di Polizia', NULL); INSERT INTO prova (idchiave, testo, testo_fts) VALUES (3, 'Operandi in una funzione', NULL); INSERT INTO prova (idchiave, testo, testo_fts) VALUES (4, 'Altro che non mi interessa', NULL); INSERT INTO prova (idchiave, testo, testo_fts) VALUES (5, 'Struttura Operativa', NULL);

-- Creo un indice per la ricerca Full Text
CREATE INDEX idx_test_fts ON prova USING gin(testo_fts) TABLESPACE tblindex;

-- Popolo il campo tsvector atto alla ricerca Full Text
UPDATE prova SET testo_fts = to_tsvector('italian', coalesce(testo,''));

-- Eseguo query per parola intera ed ottengo il risultato voluto, da notare
-- il record 5 con la declinazione al femminile.
SELECT * FROM prova where testo_fts @@ to_tsquery('italian', 'Operativo');
-- 1;"Sistema Operativo";"'oper':2 'sistem':1"
-- 2;"Operazione di Polizia";"'oper':1 'poliz':3"
-- 5;"Struttura Operativa";"'oper':2 'struttur':1"

-- Ricerca per sottostringa: manca la riga con id = 3: Operandi
SELECT * FROM prova where testo_fts @@ to_tsquery('italian', 'Oper');
-- 1;"Sistema Operativo";"'oper':2 'sistem':1"
-- 2;"Operazione di Polizia";"'oper':1 'poliz':3"
-- 5;"Struttura Operativa";"'oper':2 'struttur':1"

-- Ricerca con regexp: Funziona ma non usa gli indici (ovviamente) SELECT * FROM prova where testo ~* 'Oper';
-- 1;"Sistema Operativo";"'oper':2 'sistem':1"
-- 2;"Operazione di Polizia";"'oper':1 'poliz':3"
-- 3;"Operandi in una funzione";"'funzion':4 'operand':1"
-- 5;"Struttura Operativa";"'oper':2 'struttur':1"


-- Con una like, idem come sopra
-- SELECT * FROM prova where testo LIKE '%Oper%';
-- 1;"Sistema Operativo";"'oper':2 'sistem':1"
-- 2;"Operazione di Polizia";"'oper':1 'poliz':3"
-- 3;"Operandi in una funzione";"'funzion':4 'operand':1"
-- 5;"Struttura Operativa";"'oper':2 'struttur':1"


Ho letto che Postgresql8.4 implementarà quello che serve a me:
ricerca full-text con la possibilita' di specificare un prefisso
Ma nell'attesa come fare?

Per ora l'unica soluzione che ho trovato, ma che non ha performance
ottimali, e' quella, via trigger, di spezzare il campo 'testo' in token
e inserirli in una tabella separata sulla quale fare la join.  Una
cosa del genere:

 SELECT ... FROM prova JOIN prova_token...
 WHERE prova_token.token LIKE 'Oper%';

A questo punto uso sempre l'indice, ma la tebella dei token tende a
diventare enorme.

Ho anche provato a giocare con i trigrammi, ma non ho cavato un
ragno dal buco :-(

Mi sono perso nel classico bicchier d'acqua?

Ciao
--
Stefano Morandi  -  Linux user #147418
                    GPG key block: http://www.nephila.it/pgp

--
Per iscriversi  (o disiscriversi), basta spedire un  messaggio con OGGETTO
"subscribe" (o "unsubscribe") a mailto:linuxtrent-request@xxxxxxxxxxxxx


Other related posts: