Типы для текстового поиска

QHB предоставляет два типа данных, предназначенных для поддержки полнотекстового поиска. Текстовый поиск — это операция по выполнению поиска в коллекции документов на естественном языке с целью обнаружения тех из них, что лучше всего соответствуют запросу. Тип tsvector представляет документ в форме, оптимизированной для текстового поиска; тип tsquery аналогичным образом представляет текстовый запрос. Подробное объяснение этой возможности дается в главе Полнотекстовый поиск, а связанные с ней функции и операторы перечислены в разделе Функции и операторы текстового поиска.


tsvector

Значение типа tsvector — это упорядоченный список дискретных лексем, представляющих собой слова, которые были нормализованы для сведения различных вариантов одного и того же слова в один (подробную информацию см. в главе Полнотекстовый поиск). Сортировка и удаление дубликатов выполняются автоматически во время ввода данных, как показано в этом примере:

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

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


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.