J'aimerais savoir s'il est logique de créer un index alliant deux fonctions lors de la recherche de texte complète: lower(name)
et f_unaccent(name)
Où f_unaccent
Est juste mon wrapper à faire Fonction non accutable.
J'ai un index fonctionnant sur: f_unaccent(name)
à l'aide de varchar_pattern_ops
. Ma question est la suivante: un index qui combine lower
et unaccent
fonctions est déclenchée par FULL_TEXT_SECH lower(f_unaccent(name))
.
Je ne sais pas si la fonction lower
serait utile de travailler avec des algorithmes de recherche de texte complet.
Tout d'abord, nous devons clarifier quelques choses.
Ce type de requête peut fonctionner sur Varchar/Text Pattern_ops,
foo LIKE 'bar%'
Requêtes avec Modèles de recherche non ancrés reqire trigram
.
foo LIKE '%bar%'
Tous deux peuvent travailler sur des expressions de fonction, tant que vous maintenez la même séquence dans la requête que vous avez dans l'index.
Texte complet Recherche est quelque chose de complètement différent. Il transforme votre texte en lexemes en cas de balancement sur les mots racines, en descendant, en supprimant les mots d'arrêt et à une série d'autres astuces. Continue de lire:
Malheureusement, unaccent
n'est que "stable" pas "immuable". Et donc si vous essayez de créer un index sur unaccent(text)
vous obtiendrez une erreur, functions in index expression must be marked IMMUTABLE
. Je suppose que c'est pourquoi vous avez créé le wrapper f_accent
Ayant trouvé que sur erwins répondit sur le débordement de pile . Qui ressemble à ceci,
CREATE EXTENSION unaccent;
CREATE OR REPLACE FUNCTION f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$
LANGUAGE sql
IMMUTABLE;
CREATE TABLE foo AS
SELECT 'asdf'::text AS mytext;
CREATE INDEX ON foo (lower(f_unaccent(mytext)) text_pattern_ops);
Ou, pour Trigram,
CREATE INDEX ON foo
USING gin(lower(f_unaccent(mytext)) gin_trgm_ops);
Rappelez-vous maintenant que vous devez porter cette longue séquence lower(f_unaccent(mytext))
pour le faire fonctionner ..
SELECT *
FROM foo
WHERE lower(f_unaccent(mytext)) LIKE '%whatever%';
au lieu de cette méthode, je créerais un dictionnaire qui utilise unaccent
et utilisez FTS . Avec des dictionnaires personnalisés, même si cela fera probablement ce que vous voulez. FTS convertit les mots en jetons qui rend la recherche très simple et rapide.
CREATE EXTENSION unaccent; -- still required it plugs into FTS.
CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
ALTER MAPPING FOR hword, hword_part, Word
WITH unaccent, simple;
Maintenant, vous devriez être capable de
varchar_pattern_ops
Ou trigram
indexsi vous le souhaitez, créez A gist ou index gin sur le TSVector
CREATE INDEX ON foo USING to_tsvector('mydict', mytext);
Vous pouvez voir les jetons et ce que ça fait ici,
select to_tsvector(
'mydict',
'Zoë and Renée are elected to the council of Cheese Eating Surrender Monkeys'
);
to_tsvector
-------------------------------------------------------------------------------------------------------------------------------------
'and':2 'are':4 'cheese':10 'council':8 'eating':11 'elected':5 'monkeys':13 'of':9 'renee':3 'surrender':12 'the':7 'to':6 'zoe':1
(1 row)
Et vous pouvez interroger la table simplement comme ça,
SELECT *
FROM foo
WHERE to_tsvector('mydict', mytext) @@ 'cheese & council';
Vous n'avez pas à utiliser simple
non plus. Si la colonne contient des instructions dans une seule langue, vous pouvez utiliser l'un des autres dictionnaires Pour simplifier les choses et supprimer les mots d'arrêt.