Con la versione MySQL 5.6 sono stati introdotti gli indici Fulltext anche per InnoDB. Parliamone!
La funzionalita' di fulltext search (FTS) e' presente da sempre
sull'Engine MyISAM e, dalla release 5.6, e' disponibile anche con InnoDB.
Come usarla? Vediamo un esempio!
Con la query dell'esempio si cerca la parola "database" nel corpo di tutti gli articoli: semplice!
Riassumendo molto: nella ricerca naturale basta utilizzare la clausola MATCH nelle query indicando la colonna e la parola da ricercare. Nel 90% dei casi basta questo tipo di ricerca... ma non sempre!
Possono essere definiti indici FTS su una o piu' colonne (naturalmente di tipo testo):
la ricerca delle parole chiave
viene svolta su tutte le colonne dichiarate nell'indice.
Le colonne utilizzate nella clausola
MATCH debbono corrispondere a quelle definite nell'indice.
In caso contrario viene restituito l'errore:
ERROR 1191 (HY000): Can't find FULLTEXT index matching the column list
Se serve effettuare ricerche su piu' campi basta definire l'indice su tutti i campi desiderati:
E' tuttavia consigliabile utilizzare un solo indice con lo stesso elenco di colonne, anche perche' un indice FTS e' molto piu' pensante da mantenere rispetto ad un classico indice B-Tree.
Una variante della clausola MATCH e' quella di utilizzare il boolean mode che consente di effettuare ricerche
piu' complesse.
Ad esempio con
AGAINST ('+database -nosql' IN BOOLEAN MODE)
si cercano gli articoli che contengono la parola database ma non la parola nosql.
Sono molti gli operatori specificabili per la ricerca booleana:
Come sempre in MySQL
il tipo di ricerca dipende dalla collation utilizzata sulla colonna ricercata:
latin1_swedish_ci (il default in molti casi) e' case-insensitive mentre latin1_bin e' case-sensitive...
Per i piu' completi character set come utf8 o, meglio, utf8mb4 vi sono decine di collation disponibili
tra cui ad esempio, rispettivamente non-sensibili e sensibili al maiscolo: utf8_general_ci e utf8_bin.
E' quindi molto importante definire correttamente la collation delle colonne su cui
effettuare le ricerche altrimenti non funzioneranno;
o meglio funzioneranno perfettamente... ma non nel modo desiderato!
La clausola MATCH, oltre che nella WHERE, puo' essere utilizzata anche nella SELECT e restituisce il valore di confidenza di ogni risultato trovato:
In questo modo i risultati possono essere ordinati per rilevanza come in una ricerca su Google!
Facile vero?
Se servono ulteriori dettagli
la documentazione online
e' molto completa.
Un poco piu' complesso e' capire come funzionano gli indici FULLTEXT... per questo bisogna capirne la struttura.
Gli indici FULLTEXT esistono da sempre in MySQL [NdA in realta' dalla versione 3.23.23] ma erano disponibili solo per l'Engine MyISAM. Dalla versione MySQL 5.6 sono disponibili anche per InnoDB che e' l'Engine transazionale e nel seguito vedremo solo questa implementazione.
Una tabella InnoDB e' rappresentata dal file .frm (che contiene la definizione della tabella per tutti gli Engine) e dal tablespace dei dati contenuto nel file .ibd (nel caso di configurazione innodb_file_per_table, che e' il default).
Gli indici piu' adatti per le ricerche di tipo fulltext sono gli inverted index:
in pratica si estraggono tutte le parole piu' lunghe di innodb_ft_min_token_size (default=3)
e per ciascuna si crea la lista delle occorrenze.
Le ricerche delle parole chiave sono quindi gia' pronte
nell'indice fulltext e l'ottimizzatore deve solo raccogliere le altre condizioni della query.
Quando si creano indici di tipo fulltext search (FTS) in InnoDB
la struttura viene arricchita da nuovi tablespace
che possono essere ricercate con la query:
E corrispondono ai seguenti file:
-rw-rw---- 1 mysql mysql 4507 Feb 14 15:16 articolo.frm -rw-rw---- 1 mysql mysql 114688 Feb 14 15:16 arcicolo.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_DELETED_CACHE.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_DELETED.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_CONFIG.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_BEING_DELETED_CACHE.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_BEING_DELETED.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_6.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_5.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_4.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_3.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_2.ibd -rw-rw---- 1 mysql mysql 98304 Feb 14 15:16 FTS_0000000000000020_0000000000000023_INDEX_1.ibd
Poiche' gli inserimenti, ed ancora di piu' le cancellazioni, sono molto pesanti da gestire gli indici FTS non vengono ricalcolati ogni volta ma solo periodicamente. A volte quindi c'e'... qualche problema.
Questa sezione e' introdotta dal vostro psicologo Rogersiano...
- Ci sono problemi con gli indici fulltext?
- Tu pensi che ci siano problemi?
- Non saprei, intendo quelli introdotti nella 5.6 su InnoDB
- Dici di non saperlo per una ragione particolare?
- Non ho avuto il coraggio di utilizzarli all'inizio
- Questo e' piuttosto interessante
In effetti inizialmente era sconsigliabile utilizzare gli indici FTS InnoDB su tabelle di dimensioni significative perche' venivano allocati sulla tablespace di sistema [NdE problema risolto dalla 5.6.20].
Ovviamente piu' indici si utilizzano su una tabella piu' lente sono le operazioni di DML,
questo vale a maggior ragione per gli indici fulltext.
Poiche' le operazioni di DML sono piu' pesanti con i FULLTEXT che con i B-TREE,
a fronte di pesanti modifiche su una tabella e' spesso consigliabile rimuovere
gli indici FULLTEXT e poi ricrearli a termine dei caricamenti.
MySQL utilizza una serie di tecniche per ridurre per ottimizzare
gli indici FTS: gli inserimenti vengono effettuati solo al momento del commit
ed in caso di DELETE non viene aggiornata la chiave ma segnato come cancellato
il documento.
Chi opera sui sistemi documentali sa bene che sono necessarie periodiche attivita'
di ricostruzione degli indici...
lo stesso puo' avvenire con un FTS su InnoDB: utilizzando una normale OPTIMIZE TABLE,
operazione standard su MySQL, l'indice viene ricostruito.
In realta' gli indici FTS possono essere ricostruiti solo in parte da un'OPTIMIZE:
ma basta insistere chiamandola piu' volte!
[NdE il numero di token analizzati dall'optimize dipende dal parametro innodb_ft_num_word_optimize,
il cui default e' 2000].
Mi e' capitato qualche errore come:
InnoDB: Error (Duplicate key) writing word node to FTS auxiliary index table
che indica una corruzione nelle strutture dell'indice.
Per risolvere la sequenza corretta di operative, dalla meno invasiva e breve a quella piu' incerta, e'
la seguente:
OPTIMIZE TABLE, REPAIR TABLE, Dump&Restore, aprire una SR (Service Request), accendere un cero,
passare a...
Saro' stato fortunato... ma mi e' sempre bastato solo il primo passo lanciato un paio di volte.
Altre domande? Leggete la documentazione ufficiale!
Il parser di default utilizza gli spazi ed i caratteri di interpunzione per separare le parole... Naturalmente va bene nella maggioranza dei casi pero' per alcuni linguaggi (eg. giapponese) questo e' una limitazione perche' igiapponesiscrivonotuttoattaccato. Per superare tale limite la versione 5.7 ha aggiunto due parser Full-Text specifici: ngram e MeCab.
E' possibile modificare il comportamento delle ricerche fulltext
con alcuni parametri di tuning... ma e' fortemente sconsigliato se non in casi molto particolari.
Alcune modifiche richiedono il riavvio del server, altre la ricostruzione
di tutti gli indici, inoltre, se non si sa esattamente quello che si sta facendo,
e' molto piu' facile peggiorare le prestazioni o la qualita' delle ricerche
che migliorare qualcosa.
Per evitare complessita' quindi non vi diro' che esistono i parametri
o le posdibilita' di configurare
innodb_ft_min_token_size, innodb_ft_max_token_size,
innodb_ft_server_stopword_table, innodb_ft_user_stopword_table, innodb_ft_enable_stopword,
ngram_token_size, sql/share/charsets,
INNODB_FT_DEFAULT_STOPWORD, INNODB_FT_DELETED,
...
Titolo: InnoDB Fulltext search
Livello: Avanzato
Data: 14 Febbraio 2017
Versione: 1.0.3 -
1 Novembre 2018
Autore:
mail [AT] meo.bogliolo.name