8.11. Типы, предназначенные для текстового поиска
Postgres Pro предоставляет два типа данных для поддержки полнотекстового поиска. Текстовым поиском называется операция анализа набора документов с текстом на естественном языке, в результате которой находятся фрагменты, наиболее соответствующие запросу. Тип 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
содержит искомые лексемы, объединяемые логическими операторами &
(И), |
(ИЛИ) и !
(НЕ), а также оператором поиска фраз <->
(ПРЕДШЕСТВУЕТ). Также допускается вариация оператора ПРЕДШЕСТВУЕТ вида <
, где N
>N
— целочисленная константа, задающая расстояние между двумя искомыми лексемами. Запись оператора <->
равнозначна <1>
.
Для группировки операторов могут использоваться скобки. Без скобок эти операторы имеют разные приоритеты, в порядке убывания: !
(НЕ), <->
(ПРЕДШЕСТВУЕТ), &
(И) и |
(ИЛИ).
Несколько примеров:
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».
Апострофы в лексемах этого типа можно использовать так же, как и в лексемах в tsvector
; и так же, как и для типа tsvector
, необходимая нормализация слова должна выполняться до приведения значения к типу tsquery
. Для такой нормализации удобно использовать функцию to_tsquery
:
SELECT to_tsquery('Fat:ab & Cats'); to_tsquery ------------------ 'fat':AB & 'cat'
Заметьте, что функция to_tsquery
будет обрабатывать префиксы подобно другим словам, поэтому следующее сравнение возвращает true:
SELECT to_tsvector( 'postgraduate' ) @@ to_tsquery( 'postgres:*' ); ?column? ---------- t
так как postgres
преобразуется стеммером в postgr
:
SELECT to_tsvector( 'postgraduate' ), to_tsquery( 'postgres:*' ); to_tsvector | to_tsquery ---------------+------------ 'postgradu':1 | 'postgr':*
и эта приставка находится в преобразованной форме слова postgraduate
.