Використовуйте для цього модуль непристойного характеру , який абсолютно відрізняється від того, з чим ви посилаєтесь.
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
: