web-dev-qa-db-fra.com

Créer une recherche insensible insensible à une casse-insensible et insensible à l'accent / diagritique sur un champ

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)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.

3
Rubén_ic

Tout d'abord, nous devons clarifier quelques choses.

Motif ops et trigramme

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:

Unaccent par lui-même (ne le suggérerait pas)

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%';

Unaccent avec un dictionnaire FTS

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

  • Supprimer tout varchar_pattern_ops Ou trigram index
  • si 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.

3
Evan Carroll