8.11. Типы, предназначенные для текстового поиска
PostgreSQL предоставляет два типа данных для поддержки полнотекстового поиска. Текстовым поиском называется операция анализа набора документов с текстом на естественном языке, в результате которой находятся фрагменты, наиболее соответствующие запросу. Тип tsvector представляет документ в виде, оптимизированном для текстового поиска, а tsquery представляет запрос текстового поиска в подобном виде. Более подробно это описывается в Главе 12, а все связанные функции и операторы перечислены в Разделе 9.13.
8.11.1. tsvector
Значение типа tsvector содержит отсортированный список неповторяющихся лексем, т. е. слов, нормализованных так, что все словоформы сводятся к одной (подробнее это описано в Главе 12). Сортировка и исключение повторяющихся слов производится автоматически при вводе значения, как показано в этом примере:
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector;
tsvector
----------------------------------------------------
'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat'Для представления в виде лексем пробелов или знаков препинания их нужно заключить в апострофы:
SELECT $$the lexeme ' ' contains spaces$$::tsvector;
tsvector
-------------------------------------------
' ' 'contains' 'lexeme' 'spaces' 'the'(В данном и следующих примерах мы используем строку в долларах, чтобы не дублировать все апострофы в таких строках.) При этом включаемый апостроф или обратную косую черту нужно продублировать:
SELECT $$the lexeme 'Joe''s' contains a quote$$::tsvector;
tsvector
------------------------------------------------
'Joe''s' 'a' 'contains' 'lexeme' 'quote' 'the'Также для лексем можно указать их целочисленные позиции:
SELECT 'a:1 fat:2 cat:3 sat:4 on:5 a:6 mat:7 and:8 ate:9 a:10 fat:11
rat:12'::tsvector;
tsvector
---------------------------------------------------------------------------
'a':1,6,10 'and':8 'ate':9 'cat':3 'fat':2,11 'mat':7 'on':5 'rat':12
'sat':4Позиция обычно указывает положение исходного слова в документе. Информация о расположении слов затем может использоваться для оценки близости. Позиция может задаваться числом от 1 до 16383; большие значения просто заменяются на 16383. Если для одной лексемы дважды указывается одно положение, такое повторение отбрасывается.
Лексемам, для которых заданы позиции, также можно назначить вес, выраженный буквами A, B, C или D. Вес D подразумевается по умолчанию и поэтому он не показывается при выводе:
SELECT 'a:1A fat:2B,4C cat:5D'::tsvector;
tsvector
----------------------------
'a':1A 'cat':5 'fat':2B,4CВеса обычно применяются для отражения структуры документа, например для придания особого значения словам в заголовке по сравнению со словами в обычном тексте. Назначенным весам можно сопоставить числовые приоритеты в функциях ранжирования результатов.
Важно понимать, что тип tsvector сам по себе не выполняет нормализацию; предполагается, что в сохраняемом значении слова уже нормализованы приложением. Например:
select 'The Fat Rats'::tsvector;
tsvector
--------------------
'Fat' 'Rats' 'The' Для большинства англоязычных приложений приведённые выше слова будут считаться ненормализованными, но для tsvector это не важно. Поэтому исходный документ обычно следует обработать функцией to_tsvector, нормализующей слова:
SELECT to_tsvector('english', 'The Fat Rats');
to_tsvector
-----------------
'fat':2 'rat':3И это подробнее описано в Главе 12.
8.11.2. tsquery
Значение tsquery содержит искомые лексемы, объединённые логическими операторами & (И), | (ИЛИ) и ! (НЕ). Для группировки операторов могут использоваться скобки:
SELECT 'fat & rat'::tsquery;
tsquery
---------------
'fat' & 'rat'
SELECT 'fat & (rat | cat)'::tsquery;
tsquery
---------------------------
'fat' & ( 'rat' | 'cat' )
SELECT 'fat & rat & ! cat'::tsquery;
tsquery
------------------------
'fat' & 'rat' & !'cat' Без скобок эти операторы имеют разные приоритеты, в порядке убывания: !, & и |.
Лексемам в tsquery можно дополнительно сопоставить буквы весов, при этом они будут соответствовать только тем лексемам в tsvector, которые имеют те же веса:
SELECT 'fat:ab & cat'::tsquery;
tsquery
------------------
'fat':AB & 'cat'Кроме того, в лексемах tsquery можно использовать знак * для поиска по префиксу:
SELECT 'super:*'::tsquery; tsquery ----------- 'super':*
Этот запрос найдёт все слова в tsvector, начинающиеся с приставки «super». Заметьте, что сначала приставка обрабатывается согласно конфигурации текстового поиска, поэтому следующее сравнение возвращает true:
SELECT to_tsvector( 'postgraduate' ) @@ to_tsquery( 'postgres:*' ); ?column? ---------- t (1 row)
так как postgres преобразуется в postgr:
SELECT to_tsquery('postgres:*');
to_tsquery
------------
'postgr':*
(1 row) и эта приставка затем находится в слове postgraduate.
Апострофы в лексемах этого типа можно использовать так же, как и в лексемах в tsvector; и так же, как и для типа tsvector, необходимая нормализация слов должна выполняться до приведения значения к типу tsquery. Для такой нормализации удобно использовать функцию to_tsquery:
SELECT to_tsquery('Fat:ab & Cats');
to_tsquery
------------------
'fat':AB & 'cat'