Usa il modulo non accento per quello - che è completamente diverso da quello a cui ti stai collegando.
unaccent è un dizionario di ricerca di testo che rimuove gli accenti (segni diacritici) dai lessemi.
Installa una volta per database con:
CREATE EXTENSION unaccent;
Se ricevi un errore del tipo:
ERROR: could not open extension control file "/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Installa il pacchetto contrib sul tuo server di database come indicato in questa risposta correlata:
- Errore durante la creazione dell'estensione senza accento su PostgreSQL
Tra le altre cose, fornisce la funzione unaccent()
puoi usare con il tuo esempio (dove LIKE
sembra non necessario).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indice
Per utilizzare un indice per quel tipo di query, creare un indice sull'espressione. Tuttavia , Postgres accetta solo IMMUTABLE
funzioni per gli indici. Se una funzione può restituire un risultato diverso per lo stesso input, l'indice potrebbe interrompersi silenziosamente.
unaccent()
solo STABLE
non IMMUTABLE
Sfortunatamente, unaccent()
è solo STABLE
, non IMMUTABLE
. Secondo questo thread su pgsql-bugs, ciò è dovuto a tre motivi:
- Dipende dal comportamento di un dizionario.
- Non è presente alcuna connessione cablata a questo dizionario.
- Dipende quindi anche dal
search_path
corrente , che può cambiare facilmente.
Alcuni tutorial sul web indicano di modificare semplicemente la volatilità della funzione in IMMUTABLE
. Questo metodo di forza bruta può rompersi in determinate condizioni.
Altri suggeriscono un semplice IMMUTABLE
funzione wrapper (come ho fatto io stesso in passato).
È in corso un dibattito se realizzare la variante con due parametri IMMUTABLE
che dichiara esplicitamente il dizionario utilizzato. Leggi qui o qui.
Un'altra alternativa sarebbe questo modulo con un unaccent()
IMMUTABLE funzione di Musicbrainz, fornita su Github. Non l'ho testato da solo. Penso di aver avuto un'idea migliore :
Il migliore per ora
Questo approccio è più efficiente rispetto ad altre soluzioni in circolazione e più sicuro .
Crea un IMMUTABLE
Funzione wrapper SQL che esegue il modulo a due parametri con funzione qualificata per schema cablata e dizionario.
Poiché la nidificazione di una funzione non immutabile disabiliterebbe l'inlining della funzione, basarla su una copia della funzione C, dichiarata (falsa) IMMUTABLE
anche. È solo scopo deve essere utilizzato nel wrapper della funzione SQL. Non pensato per essere utilizzato da solo.
La sofisticatezza è necessaria in quanto non c'è modo di cablare il dizionario nella dichiarazione della funzione C. (Richiede l'hacking del codice C stesso.) La funzione SQL wrapper lo fa e consente sia l'inlining delle funzioni che indici di espressione.
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
Rilascia PARALLEL SAFE
da entrambe le funzioni per Postgres 9.5 o precedenti.
public
essendo lo schema in cui hai installato l'estensione (public
è l'impostazione predefinita).
La dichiarazione esplicita del tipo (regdictionary
) difende da ipotetici attacchi con varianti sovraccaricate della funzione da parte di utenti malintenzionati.
In precedenza, sostenevo una funzione wrapper basata su STABLE
funzione unaccent()
fornito con il modulo unaccent. Quella funzione disabilitata inlineing. Questa versione viene eseguita dieci volte più velocemente rispetto alla semplice funzione wrapper che avevo qui prima.
E questo era già due volte più veloce della prima versione che aggiungeva SET search_path = public, pg_temp
alla funzione - fino a quando non ho scoperto che anche il dizionario può essere qualificato per schema. Ancora (Postgres 12) non troppo evidente dalla documentazione.
Se ti mancano i privilegi necessari per creare funzioni C, sei tornato alla seconda migliore implementazione:An IMMUTABLE
wrapper della funzione attorno a STABLE
unaccent()
funzione fornita dal modulo:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
Infine, l'indice di espressione per effettuare query velocemente :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Ricordati di ricreare gli indici che coinvolgono questa funzione dopo qualsiasi modifica alla funzione o al dizionario, ad esempio un aggiornamento della versione principale sul posto che non ricrea gli indici. Tutte le versioni principali recenti avevano aggiornamenti per unaccent
modulo.
Adatta le query in modo che corrispondano all'indice (in modo che il pianificatore di query lo utilizzi):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Non hai bisogno della funzione nell'espressione corretta. Lì puoi anche fornire stringhe non accentate come 'Joao'
direttamente.
La funzione più veloce non si traduce in query molto più veloci utilizzando l'indice di espressione . Funziona su valori precalcolati ed è già molto veloce. Ma la manutenzione dell'indice e le query non utilizzano il vantaggio dell'indice.
La sicurezza per i programmi client è stata rafforzata con Postgres 10.3 / 9.6.8 ecc. è necessario per qualificare lo schema alla funzione e al nome del dizionario come dimostrato quando utilizzato in qualsiasi indice. Vedi:
- Voci "unaccent" non esiste nel dizionario di ricerca di testo' nel registro di Postgres, presumibilmente durante l'analisi automatica
Legature
In Postgres 9.5 o versioni precedenti legature come 'Œ' o 'ß' devono essere espanse manualmente (se necessario), poiché unaccent()
sostituisce sempre un singolo lettera:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Amerai questo aggiornamento per annullare l'accento in Postgres 9.6 :
Estendi contrib/unaccent
unaccent.rules
standard di per gestire tutti i segni diacritici noti a Unicode e espandere correttamente le legature (Thomas Munro, Léonard Benedetti)
Enfasi in grassetto mio. Ora otteniamo:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Corrispondenza del modello
Per LIKE
o LIKE
con pattern arbitrari, combinalo con il modulo pg_trgm
in PostgreSQL 9.1 o successivo. Crea un trigramma GIN (in genere preferibile) o un indice di espressione GIST. Esempio per GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Può essere utilizzato per query come:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Gli indici GIN e GIST sono più costosi da mantenere rispetto al semplice btree:
- Differenza tra indice GiST e GIN
Esistono soluzioni più semplici per i modelli ancorati a sinistra. Maggiori informazioni sulla corrispondenza dei modelli e sulle prestazioni:
- Corrispondenza del modello con LIKE, SIMILAR TO o espressioni regolari in PostgreSQL
pg_trgm
fornisce anche utili operatori per la "somiglianza" (%
) e "distanza" (<->
).
Gli indici Trigram supportano anche semplici espressioni regolari con ~
et al. e senza distinzione tra maiuscole e minuscole corrispondenza del modello con ILIKE
:
- Accento PostgreSQL + ricerca senza distinzione tra maiuscole e minuscole