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

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.