F.45. pg_trgm — поддержка сходства текста с использованием триграммного сопоставления#

F.45. pg_trgm — поддержка сходства текста с использованием триграммного сопоставления

F.45. pg_trgm — поддержка сходства текста с использованием триграммного сопоставления #

Модуль pg_trgm предоставляет функции и операторы для определения сходства алфавитно-цифрового текста на основе сопоставления триграмм, а также классы операторов индекса, которые поддерживают быстрый поиск похожих строк.

Этот модуль считается "доверенным", то есть его можно установить недоступным пользователям, у которых есть привилегия CREATE в текущей базе данных.

F.45.1. Концепции триграмм (или триграфов) #

Триграмма - это группа из трех последовательных символов, взятых из строки. Можно измерить сходство двух строк, подсчитав количество общих триграмм. Эта простая идея оказывается очень эффективной для измерения сходства слов во многих естественных языках.

Примечание

pg_trgm игнорирует несловесные символы (неалфавитно-цифровые) при извлечении триграмм из строки. Каждое слово считается имеющим два пробела в начале и один пробел в конце при определении набора триграмм, содержащихся в строке. Например, набор триграмм в строке cat состоит из c, ca, cat и at . Набор триграмм в строке foo|bar состоит из f, fo, foo, oo , b, ba, bar и ar .

F.45.2. Функции и операторы #

Список функций, предоставляемых модулем pg_trgm, приведен в таблице Таблица F.27, операторы перечислены в таблице Таблица F.28.

Таблица F.27. pg_trgm Функции

Функция

Описание

similarity ( text, text ) → real

Возвращает число, которое указывает, насколько похожи два аргумента. Диапазон результата составляет от нуля (указывает на полное отсутствие сходства двух строк) до единицы (указывает на идентичность двух строк).

show_trgm ( text ) → text[]

Возвращает массив всех триграмм в заданной строке. (На практике это редко полезно, за исключением отладки).

word_similarity ( text, text ) → real

Возвращает число, указывающее на наибольшую схожесть между набором триграмм в первой строке и любым непрерывным участком упорядоченного набора триграмм во второй строке. Подробности см. ниже.

strict_word_similarity ( text, text ) → real

То же самое, что и word_similarity, но заставляет границы extent соответствовать границам слов. Поскольку у нас нет перекрестных триграмм между словами, эта функция фактически возвращает наибольшую схожесть между первой строкой и любым непрерывным extent из слов второй строки.

show_limit () → real

Возвращает текущий порог сходства, используемый оператором %. Это устанавливает минимальное сходство между двумя словами, чтобы они считались достаточно похожими, чтобы считаться ошибками в написании друг друга, например. (Устарело; вместо этого используйте SHOW pg_trgm.similarity_threshold).

set_limit ( real ) → real

Устанавливает текущий порог сходства, который используется оператором %. Порог должен быть между 0 и 1 (по умолчанию 0.3). Возвращает переданное значение. (Устарело; вместо этого используйте SET pg_trgm.similarity_threshold).


Рассмотрим следующий пример:

# SELECT word_similarity('word', 'two words');
 word_similarity
-----------------
             0.8
(1 row)

В первой строке набор триграмм состоит из {" w"," wo","wor","ord","rd "}. Во второй строке упорядоченный набор триграмм состоит из {" t"," tw","two","wo "," w"," wo","wor","ord","rds","ds "}. Самый похожий набор триграмм второй строки это {" w"," wo","wor","ord"}, и сходство составляет 0.8.

Эта функция возвращает значение, которое можно приближенно понять как наибольшую схожесть между первой строкой и любой подстрокой второй строки. Однако эта функция не добавляет заполнение к границам области. Таким образом, количество дополнительных символов, присутствующих во второй строке, не учитывается, за исключением несовпадающих границ слов.

В то же время, strict_word_similarity выбирает набор слов во второй строке. В приведенном выше примере, strict_word_similarity выбрал бы набор из одного слова 'words', чей набор триграмм состоит из {" w"," wo","wor","ord","rds","ds "}.

# SELECT strict_word_similarity('word', 'two words'), similarity('word', 'words');
 strict_word_similarity | similarity
------------------------+------------
               0.571429 |   0.571429
(1 row)

Таким образом, функция strict_word_similarity полезна для поиска сходства с целыми словами, в то время как функция word_similarity более подходит для поиска сходства для частей слов.

Таблица F.28. pg_trgm Операторы

Оператор

Описание

text % textboolean

Возвращает true, если аргументы имеют сходство, превышающее текущий порог сходства, установленный с помощью pg_trgm.similarity_threshold.

text <% textboolean

Возвращает true, если сходство между набором триграмм в первом аргументе и непрерывным пространством упорядоченного набора триграмм во втором аргументе больше текущего порога сходства слов, установленного параметром pg_trgm.word_similarity_threshold.

text %> textboolean

Коммутатор оператора <%.

text <<% textboolean

Возвращает true, если второй аргумент имеет непрерывный набор упорядоченных триграмм, соответствующих границам слов, и его сходство с набором триграмм первого аргумента больше текущего строгого порога сходства слов, установленного параметром pg_trgm.strict_word_similarity_threshold.

text %>> textboolean

Коммутатор оператора <<%.

text <-> textreal

Возвращает расстояние между аргументами, то есть одно минус значение функции similarity().

text <<-> textreal

Возвращает расстояние между аргументами, то есть одно минус значение функции word_similarity().

text <->> textreal

Коммутатор оператора <<->.

text <<<-> textreal

Возвращает расстояние между аргументами, то есть одно минус значение strict_word_similarity().

text <->>> textreal

Коммутатор оператора <<<->.


F.45.3. Параметры GUC #

pg_trgm.similarity_threshold (real) #

Устанавливает текущий порог сходства, используемый оператором %. Порог должен быть в диапазоне от 0 до 1 (по умолчанию 0.3).

pg_trgm.word_similarity_threshold (real) #

Устанавливает текущий порог сходства слов, который используется операторами <% и %>. Порог должен быть между 0 и 1 (по умолчанию 0.6).

pg_trgm.strict_word_similarity_threshold (real) #

Устанавливает текущий строгий порог сходства слов, который используется операторами <<% и %>>. Порог должен быть между 0 и 1 (по умолчанию 0.5).

F.45.4. Поддержка индексов #

Модуль pg_trgm предоставляет классы операторов индексов GiST и GIN, которые позволяют создавать индекс по текстовому столбцу для очень быстрых поисков по схожести. Эти типы индексов поддерживают описанные выше операторы схожести, а также поддерживают поиск по индексу на основе триграмм для запросов LIKE, ILIKE, ~, ~* и =. Сравнения по схожести нечувствительны к регистру в стандартной сборке pg_trgm. Операторы неравенства не поддерживаются. Обратите внимание, что эти индексы могут быть не такими эффективными, как обычные B-деревья для оператора равенства.

Пример:

CREATE TABLE test_trgm (t text);
CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops);

или

CREATE INDEX trgm_idx ON test_trgm USING GIN (t gin_trgm_ops);

gist_trgm_ops Оператор GiST opclass приближает набор триграмм в виде битовой сигнатуры. Его необязательный целочисленный параметр siglen определяет длину сигнатуры в байтах. По умолчанию длина составляет 12 байт. Допустимые значения длины сигнатуры находятся в диапазоне от 1 до 2024 байт. Более длинные сигнатуры обеспечивают более точный поиск (сканирование меньшей доли индекса и меньшее количество страниц кучи), но требуют большего объема индекса.

Пример создания такого индекса с длиной сигнатуры 32 байта:

CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops(siglen=32));

На данном этапе у вас будет индекс на столбце t, который вы можете использовать для поиска похожих элементов. Типичный запрос выглядит так

SELECT t, similarity(t, 'word') AS sml
  FROM test_trgm
  WHERE t % 'word'
  ORDER BY sml DESC, t;

Это вернет все значения в столбце текст, которые достаточно похожи на word, отсортированные от лучшего совпадения к худшему. Индекс будет использоваться для выполнения этой операции быстро, даже при работе с очень большими наборами данных.

Вариант вышеприведенного запроса

SELECT t, t <-> 'word' AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

Это можно реализовать довольно эффективно с помощью индексов GiST, но не с помощью индексов GIN. Обычно это превосходит первую формулировку, когда требуется только небольшое количество ближайших совпадений.

Также вы можете использовать индекс на столбце t для сходства слов или строгого сходства слов. Типичные запросы:

SELECT t, word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <% t
  ORDER BY sml DESC, t;

и

SELECT t, strict_word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <<% t
  ORDER BY sml DESC, t;

Это вернет все значения в столбце текста, для которых существует непрерывное расширение в соответствующем упорядоченном наборе триграмм, которое достаточно похоже на набор триграмм word, отсортированные от лучшего совпадения к худшему. Индекс будет использован для выполнения этой операции быстро, даже для очень больших наборов данных.

Возможные варианты вышеприведенных запросов:

SELECT t, 'word' <<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

и

SELECT t, 'word' <<<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

Это можно реализовать довольно эффективно с помощью индексов GiST, но не с помощью индексов GIN.

Начиная с PostgreSQL 9.1, эти типы индексов также поддерживают поиск по индексу для LIKE и ILIKE, например

SELECT * FROM test_trgm WHERE t LIKE '%foo%bar';

Индексный поиск работает путем извлечения триграмм из поисковой строки и затем поиска их в индексе. Чем больше триграмм в поисковой строке, тем эффективнее индексный поиск. В отличие от поиска на основе B-дерева, поисковая строка не обязательно должна быть привязана к началу.

Начиная с PostgreSQL 9.3, эти типы индексов также поддерживают поиск по регулярным выражениям (операторы ~ и ~*), например

SELECT * FROM test_trgm WHERE t ~ '(foo|bar)';

Поиск по индексу работает путем извлечения триграмм из регулярного выражения и затем поиска их в индексе. Чем больше триграмм может быть извлечено из регулярного выражения, тем эффективнее будет поиск по индексу. В отличие от поиска на основе B-дерева, строка поиска не обязательно должна быть привязана к началу.

Для обоих поисков LIKE и регулярных выражений имейте в виду, что шаблон без извлекаемых триграмм будет деградировать до полного индексного сканирования.

Выбор между индексированием GiST и GIN зависит от относительных характеристик производительности GiST и GIN, которые обсуждаются в другом месте.

F.45.6. Ссылки #

Сайт разработки GiST http://www.sai.msu.su/~megera/postgres/gist/

Tsearch2 Development Site http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/

F.45.7. Авторы #

Олег Бартунов , Москва, Московский университет, Россия

Teodor Sigaev , Moscow, Delta-Soft Ltd.,Russia

Александр Коротков , Москва, Postgres Professional, Россия

Документация: Christopher Kings-Lynne

Этот модуль спонсируется компанией Delta-Soft Ltd., Москва, Россия.