вторник, 26 июня 2012 г.

PostgreSQL: текстовой поиск + латышский язык

Дано: PostgreSQL 8.3.1.

Задача: реализовать поиск по тексту независимым от латышских диакритических символов. Т.е. по запросу «ē», должны быть найдены и «e», и «ē» и наоборот. 

Латышский язык содержит следующие диакритические знаки (wikipedia):
  1. гарумзиме: ā ē ī ū,
  2. гачек: č š ž,
  3. седиль: ģ ķ ļ,
и всем этим буквам соотвествуют обычные латинские, без дополнений.

Сначала, для тех кто ищет просто решение - функция, которая заменяет буквы с диакритическими знаками на обычные:

CREATE OR REPLACE FUNCTION unaccent_string(text)
RETURNS text
 LANGUAGE SQL
 IMMUTABLE
 STRICT
AS $$

SELECT replace(
  replace(
   replace(
    replace(
     replace(
      replace(
       replace(
        replace(
         replace(
          replace(
           replace(
(
 SELECT replace(
   replace(
    replace(
     replace(
      replace(
       replace(
        replace(
         replace(
          replace(
           replace(
            replace($1, \'ā\', \'a\'),
            \'ž\', \'z\'),
           \'ū\', \'u\'),
          \'š\', \'s\'),
         \'ņ\', \'n\'),
        \'ļ\', \'l\'),
       \'ķ\', \'k\'),
      \'ī\', \'i\'),
     \'ģ\', \'g\'),
    \'ē\', \'e\'),
   \'č\', \'c\') AS "text")

            , \'Ā\', \'A\'),
           \'Ž\', \'Z\'),
          \'Ū\', \'U\'),
         \'Š\', \'S\'),
        \'Ņ\', \'N\'),
       \'Ļ\', \'L\'),
      \'Ķ\', \'K\'),
     \'Ī\', \'I\'),
    \'Ģ\', \'G\'),
   \'Ē\', \'E\'),
  \'Č\', \'C\') AS "text";
$$;

Не имея понятия с чего начать, я попытался найти какое-то готовое решение. Мне попалась идея замены букв на обычные с помощью функции translate(). Отсюда и начал:

~~
SELECT translate('Cātozzo', 't', 'a2') AS "res"

res: Cāaozzo
~~

простой символ заменяется как и ожидалось, но:

~~
SELECT translate('Cātozzo', 'ā', 'a2') AS "res"

res: Ca2tozzo
~~

utf-символ воспринимается функцией translate как два, и каждая половинка заменяется отдельно (таков принцип работы функции). Первая часть utf-символа повторяется у разных букв, поэтому вариант с translate() не работает или сильно усложняется.

Тогда я решил попробовать replace, что и дало мне функцию указанную вначале статьи. Тест:

~~
SELECT unaccent_string(\'glāžšķūņu rūķīši\') AS "res"

res: glazskunu rukisi

SELECT unaccent_string(\'GLĀŽŠĶŪŅU RŪĶĪŠI\') AS "res"

res: GLAZSKUNU RUKISI
~~


Комментариев нет:

Отправить комментарий