MySQL offre l'opportunità di effettuare particolari ricerche, dette full-text, su campi di testo anche piuttosto estesi. La caratteristica speciale di queste ricerche è che non si limitano a rintracciare le occorrenze di una parola o di una frase – al pari di quello che potrebbe fare l'operatore LIKE
– ma individuano le righe in cui il campo o i campi sottoposti alla ricerca mostrano un'attinenza particolare con il pattern indicato.
È una caratteristica che assomiglia poco ad un comune filtro e molto di più a quelle forme di valutazione utili nei motori di ricerca o nei CMS (Content Management System), usate in moltissimi blog.
Gli indici FULLTEXT e la funzione MATCH
Tali ricerche possono essere eseguite su uno o più campi ma richiedono la presenza di un FULLTEXT INDEX
che li coinvolga tutti.
La definizione seguente crea un tabella con un indice FULLTEXT
applicato ad un campo solo:
CREATE TABLE Blog
(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50),
body TEXT,
FULLTEXT (body)
)
Come si vede, è sufficiente indicare la parola chiave FULLTEXT
ed elencare, tra parentesi tonde, i campi coinvolti.
È bene comunque ricordare che tali indici possono essere creati solo su campi di testo (VARCHAR
, TEXT
, CHAR
) e con gli Storage Engine MyISAM ed InnoDB. In particolare, su quest'ultimo motore sono permessi solo a partire dalla versione 5.6 del DBMS.
La ricerca potrà essere effettuata usando il costrutto MATCH ... AGAINST
:
SELECT * FROM Blog WHERE MATCH (body) AGAINST ('database');
Questa query effettuerà una ricerca sul campo body
della tabella Blog
usando il termine database
come pattern.
Nella clausola MATCH
possono essere inclusi più campi, ma è fondamentale che tutti facciano parte dell'indice FULLTEXT
creato. È altrettanto essenziale che, se l'indice include più campi, tutti vengano nominati nella clausola MATCH
.
La rilevanza
Il risultato della funzione MATCH
è un valore in virgola mobile, non negativo, che rappresenta la rilevanza di ogni record recuperato alla luce della ricerca effettuata. Ciò rappresenta la principale differenza rispetto ai filtri più comuni e meno complessi: il risultato non ci dice solot se una stringa appartiene al campo o meno, ma cerca anche di capire se esiste un'attinenza tra il pattern ricercato ed i contenuti.
Per vedere i valori che la rilevanza può assumere, si esegua una query di questo tipo:
> select id,MATCH(body) AGAINST ('archivio fisico') from Blog;
1 0
3 0.6695559024810791
2 0.6801062822341919
4 0
5 0
La tabella Blog
contiene alcuni post campione che trattano di database. Abbiamo cercato nel campo body
il testo “archivio fisico” e sono stati segnalati, in base alla rilevanza, due record:
-
il record con
id
pari a 2, contenente l'espressione “...l'archivio fisico...”; -
il record con
id
pari a 3, contenente la stringa “...l'archivio a livello fisico...”.
Entrambi vengono ritenuti interessanti ai fini della ricerca pertanto i livelli di rilevanza calcolati sono significativi. Il voto ottenuto dal post con id
pari a 2 è leggermente superiore in quanto contiene un'espressione più calzante con il pattern.
Per ottenere solo i post rilevanti possiamo eseguire la query successiva che include l'uso di MATCH
all'interno della clausola WHERE
.
> select id, MATCH(body) AGAINST ('archivio fisico') from Blog where MATCH(body) AGAINST ('archivio fisico');
2 0.6801062822341919
3 0.6695559024810791
Nonostante il costrutto MATCH...AGAINST
appaia due volte volte, l'ottimizzatore del DBMS riesce a percepire che si tratta della medesima espressione e la calcola una sola volta.
Inoltre, il fatto che i risultati vengano forniti in ordine decrescente di rilevanza non è casuale: questo è infatti il comportamento di default.
Modificatori di ricerca
All'interno della clausola AGAINST
, subito dopo il pattern di ricerca, possono essere inclusi dei modificatori.
Quello di default è IN NATURAL LANGUAGE MODE. In pratica, scrivere AGAINST ('archivio fisico')
oppure AGAINST ('archivio fisico' IN NATURAL LANGUAGE MODE)
produce il medesimo effetto.
Questo modificatore effettua una ricerca considerando che il pattern proposto viene scritto in linguaggio naturale, quello spontaneo per l'essere umano, implementando quindi un'attività da tipico motore di ricerca.
In casi in cui il pattern di ricerca sia troppo corto, la rilevanza ottenuta potrebbe essere bassa. Si può pertanto richiedere una ricerca con “espansione delle query” utilizzando il modificatore WITH QUERY EXPANSION
o IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
.
Questa modalità di ricerca effettuerà il procedimento due volte: prima cerca il pattern così come fornito; la seconda volta, invece, associa al pattern i contenuti più rilevanti individuati nella prima ricerca. Ciò, tipicamente, produrrà un maggior numero di documenti rilevanti riscontrati.
Un'ultima tipologia di ricerca è detta booleana e introdotta dal modificatore IN BOOLEAN MODE.
Utilizza simboli +
e –
per indicare, all'interno del pattern, se la parola deve essere contenuta (+
) o no (-
).
Ad esempio, la clausola AGAINST('+cane -gatto' IN BOOLEAN MODE)
specifica che il pattern è inteso per rilevare i post che contengono il termine 'cane' ma non 'gatto'. A livello di logica booleana, il simbolo +
corrisponde ad un AND, il -
ad un NOT, mentre l'assenza di simbolo corrisponde ad un OR.
Il motore InnoDB accetta tali simboli solo se precedono il termine, ma si tratta di una restrizione in quanto, secondo le regole generali di MySQL, tali simboli possono anche seguire la parola cui si riferiscono.