PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL поддържа ли съпоставяния, нечувствителни към акцента?

Използвайте модула без акценти за това - което е напълно различно от това, към което се свързвате.

unaccent е речник за текстово търсене, който премахва ударенията (диакритични знаци) от лексемите.

Инсталирайте веднъж на база данни с:

CREATE EXTENSION unaccent;

Ако получите грешка като:

ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory

Инсталирайте пакета contrib на вашия сървър на база данни, както е указано в този свързан отговор:

  • Грешка при създаване на разширение без акцент на PostgreSQL

Освен всичко друго, той предоставя функцията unaccent() можете да използвате с вашия пример (където LIKE изглежда не е необходимо).

SELECT *
FROM   users
WHERE  unaccent(name) = unaccent('João');

Индекс

За да използвате индекс за този вид заявка, създайте индекс на израза. Въпреки това , Postgres приема само IMMUTABLE функции за индекси. Ако функцията може да върне различен резултат за същия вход, индексът може тихо да се счупи.

unaccent() само STABLE не IMMUTABLE

За съжаление, unaccent() е само STABLE , а не IMMUTABLE . Според тази тема за pgsql-бъгове, това се дължи на три причини:

  1. Зависи от поведението на речника.
  2. Няма кабелна връзка с този речник.
  3. Следователно зависи и от текущия search_path , което може лесно да се промени.

Някои уроци в мрежата инструктират просто да промените волатилността на функцията на IMMUTABLE . Този метод на груба сила може да се счупи при определени условия.

Други предлагат прост IMMUTABLE функция за обвивка (както правех самият аз в миналото).

Продължава дебат дали да се направи вариантът с два параметъра IMMUTABLE който изрично декларира използвания речник. Прочетете тук или тук.

Друга алтернатива би бил този модул с НЕИЗМЕНЕН unaccent() функция от Musicbrainz, предоставена на Github. Не съм го тествал лично. Мисля, че ми хрумнапо-добра идея :

Най-доброто за сега

Този подход е по-ефективен от другите решения, които се носят наоколо, и по-безопасен .
Създайте IMMUTABLE Функция за обвивка на SQL, изпълняваща двупараметърната форма с функция и речник, квалифицирана по твърда схема.

Тъй като влагането на непроменяема функция би деактивирало вграждането на функцията, базирайте я на копие на C-функцията, (фалшива) декларирана IMMUTABLE също така. Това е единствено целта е да се използва в обвивката на SQL функцията. Не е предназначен да се използва самостоятелно.

Усъвършенстването е необходимо, тъй като няма начин за твърдо свързване на речника в декларацията на функцията C. (Трябва да се хакне самия C код.) Функцията за обвивка на SQL прави това и позволява и двете функции, вграждащи и индекси на изрази.

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$;

Пуснете PARALLEL SAFE от двете функции за Postgres 9.5 или по-стара версия.

public е схемата, където сте инсталирали разширението (public е по подразбиране).

Изричната декларация за тип (regdictionary ) защитава срещу хипотетични атаки с претоварени варианти на функцията от злонамерени потребители.

Преди това се застъпвах за функция за обвиване, базирана на STABLE функция unaccent() доставя се с модула без акцент. Тази деактивирана функция вграждане. Тази версия се изпълнява десет пъти по-бързо отколкото простата функция за обвивка, която имах тук по-рано.
И това вече беше два пъти по-бързо от първата версия, която добави SET search_path = public, pg_temp към функцията - докато не открих, че речникът също може да бъде квалифициран по схема. Все пак (Postgres 12) не е твърде очевидно от документацията.

Ако липсват ви необходимите привилегии за създаване на C функции, вие се връщате към втората най-добра реализация:IMMUTABLE обвивка на функцията около STABLE unaccent() функция, предоставена от модула:

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;

И накрая, индексът на изразите за да правите заявки бързи :

CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));

Не забравяйте да пресъздадете индекси включваща тази функция след всяка промяна на функция или речник, като основно надграждане на изданието на място, което няма да пресъздава индекси. Всички последни големи издания имаха актуализации за unaccent модул.

Адаптирайте заявките, за да съответстват на индекса (така че планировщикът на заявки ще го използва):

SELECT * FROM users
WHERE  f_unaccent(name) = f_unaccent('João');

Нямате нужда от функцията в правилния израз. Там можете също да предоставите низове без ударение като 'Joao' директно.

По-бързата функция не се превежда в много по-бързи заявки, използващи индекса на изразите . Това работи с предварително изчислени стойности и вече е много бързо. Но поддръжката на индекса и заявките, които не използват ползата от индекса.

Сигурността на клиентските програми е засилена с Postgres 10.3 / 9.6.8 и др. Имате нужда за квалифициране по схема на функция и име на речник, както е показано, когато се използва във всички индекси. Вижте:

  • „записи в речника за търсене на текст „unaccent“ не съществува“ в дневника на postgres, вероятно по време на автоматичен анализ

Лигатури

В Postgres 9.5 или по-стара версия лигатури като 'Œ' или 'ß' трябва да се разширяват ръчно (ако имате нужда от това), тъй като unaccent() винаги замества единично писмо:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
E A e a S

Ще ви хареса тази актуализация за премахване на акцента в Postgres 9.6 :

Разширете contrib/unaccent стандартен unaccent.rules файл за обработка на всички диакритични знаци, известни на Unicode, и правилно разширяване на лигатурите (Томас Мунро, Леонард Бенедети)

Удебелен акцент мой. Сега получаваме:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
OE AE oe ae ss

Съвпадение на шаблон

За LIKE или ILIKE с произволни шаблони, комбинирайте това с модула pg_trgm в PostgreSQL 9.1 или по-нова версия. Създайте триграма GIN (обикновено за предпочитане) или GIST изразен индекс. Пример за GIN:

CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);

Може да се използва за заявки като:

SELECT * FROM users
WHERE  f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');

Индексите GIN и GIST са по-скъпи за поддръжка от обикновените btree:

  • Разлика между GiST и GIN индекс

Има по-прости решения само за ляво закотвени шаблони. Повече за съвпадението на шаблоните и производителността:

  • Съвпадение на образец с LIKE, SIMILAR TO или регулярни изрази в PostgreSQL

pg_trgm също така предоставя полезни оператори за "подобие" (% ) и "разстояние" (<-> ).

Индексите на триграма също поддържат прости регулярни изрази с ~ et al. и нечувствителни на главни букви съвпадение на модел с ILIKE :

  • PostgreSQL акцент + търсене без значение на главни букви


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Експортиране на PostgreSQL база данни с phpPgAdmin

  2. Как да променя позицията на колона в таблица с база данни на PostgreSQL?

  3. sql ПОРЪЧАЙТЕ ПО множество стойности в определен ред?

  4. Грешка в Postgres:не можа да се отвори файл за четене:Разрешението е отказано

  5. Скорост на съкращаване на Postgresql