В данном разделе описываются дополнительные функции и операторы, используемые совместно с текстовым поиском.
Раздел 2.9.3.1 показано, как исходные текстовые
документы могут быть преобразованы в tsvector значений.
Digital Q.DataBase также предоставляет функции и операторы, которые могут быть использованы для обработки документов, уже представленных в tsvector форме.
tsvector || tsvector
Данный tsvector оператор конкатенации
возвращает вектор, объединяющий лексемы и позиционную информацию
двух векторов, переданных в качестве аргументов. Позиции и весовые метки
сохраняются в процессе выполнения конкатенации.
Позиции, представленные в правом векторе, смещаются на величину наибольшей
позиции, указанной в левом векторе, вследствие чего результат становится
практически эквивалентным результату выполнения операции to_tsvector
над конкатенацией двух исходных текстовых строк документов. (Данная
эквивалентность не является абсолютной, поскольку любые стоп-слова, удаленные из
конца левого аргумента, не влияют на итоговый результат, в то время как
они повлияли бы на позиции лексем в
правом аргументе при использовании обычной текстовой конкатенации.)
Одним из преимуществ использования конкатенации в векторной форме, в отличие от
объединения текста перед применением функции to_tsvector, является то, что
система позволяет использовать различные конфигурации для синтаксического анализа разных разделов
документа. Кроме того, поскольку setweight функция
помечает все лексемы заданного вектора одинаковым образом, необходимо
выполнить разбор текста и вызвать функцию setweight перед выполнением конкатенации
, если требуется пометить разные части документа различными
весами.
setweight(vector tsvector, вес "char") возвращает tsvector
setweight возвращает копию входного вектора, в которой каждой
позиции присвоена заданная метка вес, либо
A, B, C, или
D. (D используется по умолчанию для новых
векторах и как таковые не отображаются при выводе). Данные метки
сохраняются при конкатенации векторов, что позволяет назначать словам из различных
частей документа разные веса с помощью функций ранжирования.
Обратите внимание, что метки веса применяются к позициям, а не к
лексемы. Если из входного вектора были удалены
позиции, то функция setweight не выполняет никаких действий.
length(vector tsvector) возвращает integer
Возвращает количество лексем, хранящихся в векторе.
strip(vector tsvector) возвращает tsvector
Возвращает вектор, содержащий те же лексемы, что и исходный вектор, но
без какой-либо информации о позициях или весах. Результат обычно значительно
меньше по размеру, чем вектор с сохраненными данными, но он также менее полезен.
Ранжирование по релевантности работает с очищенными векторами менее эффективно, чем
неочищенных значений. Кроме того,
соответствующий <-> (FOLLOWED BY) tsquery оператор
никогда не будет соответствовать очищенным входным данным, так как не сможет определить
расстояние между вхождениями лексем.
Полный список tsvectorсвязанных функций доступен
в Таблица 2.6.43.
Раздел 2.9.3.2 было показано, как необработанные текстовые
запросы могут быть преобразованы в tsquery значений.
Digital Q.DataBase также предоставляет функции и операторы, которые могут быть использованы для управления запросами, уже представленными в формате tsquery форме.
tsquery && tsquery
Возвращает результат объединения двух заданных запросов по условию AND.
tsquery || tsquery
Возвращает результат объединения двух заданных запросов по условию OR.
!! tsquery
Возвращает отрицание (NOT) заданного запроса.
tsquery <-> tsquery
Возвращает запрос, выполняющий поиск совпадения с первым указанным запросом,
сразу за которым следует совпадение со вторым указанным запросом, с использованием
соответствующий <-> (FOLLOWED BY)
tsquery оператора. Например:
SELECT to_tsquery('fat') <-> to_tsquery('cat | rat');
?column?
----------------------------
'fat' <-> ( 'cat' | 'rat' )
tsquery_phrase(query1 tsquery, query2 tsquery [, distance integer ]) возвращает tsquery
Возвращает запрос, выполняющий поиск совпадения с первым указанным запросом,
за которым следует совпадение со вторым указанным запросом на расстоянии ровно
distance лексем, используя
соответствующий <
N>tsquery оператора. Например:
SELECT tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'), 10);
tsquery_phrase
------------------
'fat' <10> 'cat'
numnode(запросу tsquery) возвращает integer
Возвращает количество узлов (лексем и операторов) в объекте
tsquery. Данная функция полезна
для определения того, является ли поисковый запрос запросу значимым
(возвращает значение > 0) или же он содержит только стоп-слова (возвращает 0).
Примеры:
SELECT numnode(plainto_tsquery('the any'));
NOTICE: query contains only stopword(s) or doesn't contain lexeme(s), ignored
numnode
---------
0
SELECT numnode('foo & bar'::tsquery);
numnode
---------
3
querytree(запросу tsquery) возвращает текстовые
Возвращает часть выражения tsquery которая может быть использована для
поиска по индексу. Данная функция полезна для обнаружения
неиндексируемых запросов, например тех, которые содержат только стоп-слова
или только термы с отрицанием. Пример:
SELECT querytree(to_tsquery('defined'));
querytree
-----------
'defin'
SELECT querytree(to_tsquery('!defined'));
querytree
-----------
T
Семейство ts_rewrite функций выполняет поиск в заданном объекте tsquery для поиска вхождений целевого подзапроса и замены каждого такого вхождения замещающим подзапросом. По сути, данная операция представляет собой
tsquery— это специализированная версия замены подстроки.
Комбинацию целевого выражения и замены можно
рассматривать как правило перезаписи запроса. Набор
таких правил перезаписи может служить мощным средством поиска.
Например, можно расширить область поиска, используя синонимы
(например, new york, big apple, nyc,
gotham) или сузить поиск, чтобы направить пользователя к определенной актуальной теме. Данный функционал частично совпадает с возможностями тезаурусов (Раздел 2.9.6.4).
Однако набор правил перезаписи можно изменять «на лету» без
переиндексирования, тогда как обновление тезауруса требует
повторного индексирования для применения изменений.
ts_rewrite (запросу tsquery, target tsquery, substitute tsquery) возвращает tsquery
Данная форма ts_rewrite просто применяет одиночное
правило перезаписи: target
заменяется на substitute
везде, где оно встречается в запросу. Например:
SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery);
ts_rewrite
------------
'b' & 'c'
ts_rewrite (запросу tsquery, Вариант функции с SQL-запросом SELECT текстовые) возвращает tsquery
Данная форма ts_rewrite принимает исходный объект tsquery
запросу и SQL-команду Вариант функции с SQL-запросом SELECT SELECT, которая
задается в виде текстовой строки. Данная команда Вариант функции с SQL-запросом SELECT должна возвращать два
столбца типа tsquery. Для каждой строки tsquery полученного результата
Вариант функции с SQL-запросом SELECT вхождения значения из первого столбца
(целевой объект) заменяются значением из второго столбца (подстановочный объект)
в текущем запросу обрабатываемом значении. Например:
CREATE TABLE aliases (t tsquery PRIMARY KEY, s tsquery);
INSERT INTO aliases VALUES('a', 'c');
SELECT ts_rewrite('a & b'::tsquery, 'SELECT t,s FROM aliases');
ts_rewrite
------------
'b' & 'c'
Обратите внимание: когда подобным образом применяются несколько правил переписывания,
порядок их применения может иметь значение; поэтому на практике
вам может потребоваться, чтобы исходный запрос ORDER BY некоторый ключ упорядочивания.
Рассмотрим практический пример из области астрономии. Выполним расширение запроса
supernovae с использованием правил перезаписи на основе таблиц:
CREATE TABLE aliases (t tsquery primary key, s tsquery);
INSERT INTO aliases VALUES(to_tsquery('supernovae'), to_tsquery('supernovae|sn'));
SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
ts_rewrite
---------------------------------
'crab' & ( 'supernova' | 'sn' )
Изменить правила перезаписи можно путем простого обновления данных в таблице:
UPDATE aliases
SET s = to_tsquery('supernovae|sn & !nebulae')
WHERE t = to_tsquery('supernovae');
SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
ts_rewrite
---------------------------------------------
'crab' & ( 'supernova' | 'sn' & !'nebula' )
Процесс перезаписи может замедляться при большом количестве правил, так как система проверяет каждое правило на предмет возможного соответствия. Для исключения заведомо неподходящих правил можно использовать операторы включения для tsquery
типа данных. В приведенном ниже примере выбираются только те правила, которые могут соответствовать исходному запросу:
SELECT ts_rewrite('a & b'::tsquery,
'SELECT t,s FROM aliases WHERE ''a & b''::tsquery @> t');
ts_rewrite
------------
'b' & 'c'
Метод, описанный в данном разделе, считается устаревшим в связи с появлением хранимых генерируемых столбцов (generated columns), как описано в Раздел 2.9.2.2.
При использовании отдельного столбца для хранения tsvector представления
документов необходимо создать триггер для обновления значения в данном
tsvector столбце при изменении исходного содержимого документа.
Для этой задачи доступны две встроенные триггерные функции, либо вы можете разработать
собственную.
tsvector_update_trigger(tsvector_column_name,config_name,text_column_name[, ... ]) tsvector_update_trigger_column(tsvector_column_name,config_column_name,text_column_name[, ... ])
Данные триггерные функции автоматически вычисляют значение tsvector
столбца на основе одного или нескольких текстовых полей согласно параметрам, указанным в команде CREATE TRIGGER .
Пример их использования:
CREATE TABLE messages (
title text,
body text,
tsv tsvector
);
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON messages FOR EACH ROW EXECUTE FUNCTION
tsvector_update_trigger(tsv, 'pg_catalog.english', title, body);
INSERT INTO messages VALUES('title here', 'the body text is here');
SELECT * FROM messages;
заголовок | body | tsv
------------+-----------------------+----------------------------
title here | the body text is here | 'bodi':4 'text':5 'titl':1
SELECT title, body FROM messages WHERE tsv @@ to_tsquery('title & body');
заголовок | body
------------+-----------------------
title here | the body text is here
После создания данного триггера любое изменение в заголовок или
body будет автоматически отражаться в столбце
tsv, без необходимости внесения изменений в логику работы приложения.
Первый аргумент триггера должен содержать имя tsvector
обновляемого столбца. Второй аргумент определяет конфигурацию текстового поиска, используемую для выполнения преобразования. Для функции
tsvector_update_triggerимя конфигурации просто указывается во втором аргументе триггера. Имя конфигурации должно быть квалифицировано именем схемы, как показано выше, чтобы поведение триггера не зависело от изменений в search_path. Для функции
tsvector_update_trigger_column, вторым аргументом триггера является имя другого столбца таблицы, который должен иметь тип
regconfig. Это позволяет выбирать конфигурацию текстового поиска индивидуально для каждой строки. Остальные аргументы представляют собой имена текстовых столбцов (имеющих тип текстовые, varchar, или char). Указанные значения будут включены в документ в заданном порядке. Значения NULL будут пропущены (при этом индексирование остальных столбцов всё равно будет выполнено).
Ограничение данных встроенных триггеров заключается в том, что все входные столбцы обрабатываются ими одинаково. Для дифференцированной обработки столбцов — например, для присвоения заголовку иного веса, чем основному тексту, — необходимо написать пользовательский триггер. Ниже приведен пример использования языка PL/pgSQL для реализации триггера:
CREATE FUNCTION messages_trigger() RETURNS trigger AS $$
begin
new.tsv :=
setweight(to_tsvector('pg_catalog.english', coalesce(new.title,'')), 'A') ||
setweight(to_tsvector('pg_catalog.english', coalesce(new.body,'')), 'D');
return new;
end
$$ LANGUAGE plpgsql;
CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
ON messages FOR EACH ROW EXECUTE FUNCTION messages_trigger();
Следует учитывать, что при формировании значений внутри триггеров важно tsvector явно указывать имя конфигурации полнотекстового поиска,
чтобы на содержимое столбца не влияли изменения параметров
default_text_search_config. Несоблюдение этого требования может привести к возникновению таких проблем, как изменение результатов поиска после выполнения выгрузки и восстановления базы данных.
Функция ts_stat полезна для проверки текущей конфигурации и поиска потенциальных стоп-слов.
ts_stat(sqlqueryтекстовые, [weightsтекстовые, ] OUTwordтекстовые, OUTndocinteger, OUTnentryinteger) возвращаетsetof record
sqlquery представляет собой текстовое значение, содержащее SQL-запрос, который должен возвращать один tsvector столбец.
ts_stat выполняет запрос и возвращает статистические данные о каждой уникальной лексеме (слове), содержащейся в tsvector
данных. Функция возвращает следующие столбцы:
word текстовые — значение лексемы
ndoc integer — количество документов
(tsvectorв которых встречается данное слово
nentry integer — общее количество
вхождений данного слова
Если weights указан, учитываются только те вхождения, которые имеют один из данных весов.
Например, чтобы найти десять наиболее часто встречающихся слов в коллекции документов:
SELECT * FROM ts_stat('SELECT vector FROM apod')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;
То же самое, но с подсчётом вхождений слов только с весом A
или B:
SELECT * FROM ts_stat('SELECT vector FROM apod', 'ab')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;