Використовуйте для цього модуль непристойного характеру , який абсолютно відрізняється від того, з чим ви посилаєтесь.
unaccent - це текстовий словник пошуку, який видаляє наголоси (діакритичні знаки) з лексеми.
Встановіть один раз у базі даних за допомогою:
CREATE EXTENSION unaccent;
Якщо ви отримаєте помилку, наприклад:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Встановіть пакунок contrib на свій сервер бази даних, як зазначено в цій відповіді:
Крім усього іншого, він надає функцію, unaccent()яку ви можете використовувати зі своїм прикладом (де, LIKEздається, не потрібно).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Покажчик
Щоб використовувати індекс для такого типу запиту, створіть індекс на виразі . Однак Postgres приймає лише IMMUTABLEфункції для індексів. Якщо функція може повернути інший результат за один і той же вхід, індекс може мовчки зламатися.
unaccent()тільки STABLEніIMMUTABLE
На жаль, unaccent()є тільки STABLE, ні IMMUTABLE. Відповідно до цієї теми на pgsql-bugs , це пов'язано з трьома причинами:
- Це залежить від поведінки словника.
- Немає жодного провідного зв’язку з цим словником.
- Тому це також залежить від струму
search_path, який може легко змінитися.
Деякі підручники в Інтернеті вказують просто змінити волатильність функції IMMUTABLE. Цей метод грубої сили може порушитись за певних умов.
Інші пропонують просту IMMUTABLEфункцію обгортки (як я це робив у минулому).
Триває дискусія щодо того, чи робити варіант із двома параметрами, IMMUTABLE який чітко оголошує використаний словник. Прочитайте тут або тут .
Іншою альтернативою став би цей модуль з незмінною unaccent()функцією Musicbrainz , наданий на Github. Я не перевіряв його сам. Я думаю, що я придумав кращу ідею :
Найкраще зараз
Цей підхід є більш ефективним, оскільки інші рішення, що плавають навколо, і безпечніший .
Створіть функцію IMMUTABLEобгортки SQL, виконуючи форму з двома параметрами за допомогою жорсткої провідної схеми та функції словника.
Оскільки введення незмінювальної функції призведе до відключення функції вбудовування, базуйте її також на копії заявленої C-функції (підробленої) IMMUTABLE. Його тільки мета полягає в тому, щоб використовувати в функції SQL обгортку. Не призначений для використання самостійно.
Витонченість потрібна, оскільки немає можливості затягувати словник у декларації функції С. (Буде потрібно зламати сам код 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 і т.д. Ви потрібні для схеми-кваліфікуватися функціями і ім'я словника , як показано при використанні в будь-яких індексах. Побачити:
Лігатури
У 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:
Існують більш прості рішення для лише ліворізаних моделей. Докладніше про відповідність шаблону та ефективність:
pg_trgmтакож надає корисні оператори для "подібності" ( %) та "відстані" ( <->) .
Індекси триграму також підтримують прості регулярні вирази з ~співавт. і нечутливий рисунок регістру, що відповідає ILIKE: