12.4. 附加功能
本节描述了连接文本搜索中有用的附加功能和操作符。
12.4.1. 操作文档
节Section 12.3.1显示了原始文本文档如何转换成tsvector
值。 PostgreSQL也提供用于操作已经在tsvector
形式中的文档的函数和操作符。
tsvector
|| tsvector
tsvector
连接操作符返回一个连接词的向量,以及作为参数给定的2个向量的位置信息。 在连接期间重新获得位置和权重标签。出现在右边向量位置通过左边向量提到的最大位置相抵消, 因此这个结果几乎等同于2个原始文档字符串连接中执行to_tsvector
的结果。(这个等价是不准确的, 因为任何从左边参数中删除的屏蔽词不会影响结果,然而,如果使用文本连接,它们影响右边参数词的位置)。
使用级联中的向量形式而不是在应用to_tsvector
之前连接文本的一个优势是, 你可以使用不同的配置解析文档的不同部分。同时,由于setweight
函数标记所有相同方式给定向量的词汇, 解析文本是必要的,并且如果你想用不同的权重标记文档不同部分,连接前做setweight
。
setweight(``_vector_
tsvector
, _weight_
"char"
) returns tsvector
setweight
返回一个输入向量的拷贝,其中每一个位置用给定的_weight_
, A
, B
, C
或者 D
之一进行标记。(D
是缺省新向量,因此不显示在输出上。)当向量连接时,保留这些标签, 允许一个文档的不同部分的词通过不同相关函数加权。
注意权重标签适用于位置,不是词汇。如果输入向量已经被剥夺了位置,则setweight
不做任何事情。
length(``_vector_
tsvector
) returns integer
返回存储在向量中的词的数量。
strip(``_vector_
tsvector
) returns tsvector
返回一个向量,其中列出了给定向量的同一词,但它缺乏任何位置和权重信息。 虽然为相关性排序返回的向量比一个未拆分向量用处少,它通常会小得多。
12.4.2. 处理查询
节Section 12.3.2显示了原始文本查询如何转换成tsquery
值。 PostgreSQL也提供了函数和操作符用于处理已存在tsquery
形式中的查询
tsquery
&& tsquery
返回两个给定查询的与组合。
tsquery
|| tsquery
返回两个给定查询的或组合。
!!
tsquery
返回给定查询的反面(非)。
numnode(``_query_
tsquery
) returns integer
返回在一个tsquery
中节点的数目(词加操作符)。决定_query_
是否有意义(返回> 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(``_query_
tsquery
) returns text
返回可用于搜索索引的tsquery
部分。此函数对检测未索引查询是有帮助的,例如那些只包含屏蔽词或否定术语。比如:
SELECT querytree(to_tsquery('!defined'));
querytree
-----------
12.4.2.1. 查询重写
函数族ts_rewrite
搜索一个特定的目标查询事件tsquery
,和替换每个替代子查询。 实际上这个操作是一个子字符串替换的tsquery
-特定版本。目标和替换组合可以被认为是一个查询重写规则。 一组这样的重写规则可以是一个强大的搜索帮助。例如,你可以使用同义词扩大搜索(例如,new york
, big apple
, nyc
, gotham
)或缩小搜索一些热点问题的直接用户。在这些特性和同义词词典之间功能上有一些重叠(节Section 12.6.4)。然而, 你可以在不重建索引情况下即时修改重写规则,而更新词库需要重建索引才能有效。
ts_rewrite (``_query_
tsquery
, _target_
tsquery
, _substitute_
tsquery
) returns tsquery
ts_rewrite
的这种形式只适用于一个单一的重写规则:无论出现在_query_
的什么地方,_target_
通过_substitute_
替换。比如:
SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery);
ts_rewrite
------------
'b' & 'c'
ts_rewrite (``_query_
tsquery
, _select_
text
) returns tsquery
ts_rewrite
的这种形式接受起始_查询_
和SQL _select_
命令,这是作为一个文本字符串。 _select_
必须产生两列tsquery
类型。_select_
结果的每一行,出现的第一个字段的值(目标) 都被当前的_query_
值中的第二个字段值(替代)。比如:
注意,当多个重写规则适用于这种方式时,应用的顺序非常重要; 因此在实践中你将需要源查询为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'
12.4.3. 自动更新的触发器
当使用单独的列存储文档的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 PROCEDURE
tsvector_update_trigger(tsv, 'pg_catalog.english', title, body);
INSERT INTO messages VALUES('title here', 'the body text is here');
SELECT * FROM messages;
title | 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');
title | body
------------+-----------------------
title here | the body text is here
创建触发器,在title
或者body
中的任何改变都会自动反映到tsv
中,而不必担心它的应用。
第一个触发器参数必须是被更新的tsvector
字段名。第二个参数指定要进行转换的文本搜索配置。 为tsvector_update_trigger
,配置的名称仅仅是作为第二个触发器参数。它必须是如上所示的模式匹配, 因此触发器的行为在search_path
中不会改变。为tsvector_update_trigger_column
, 第二个触发器参数是另一个表列的名称,它的类型必须是regconfig
。这允许每行选择进行配置。 剩余的参数(s)是文本列的名称(键入text
, varchar
或者char
)。这些将在给定的顺序中提供文档。 空值将被忽略(但其他列仍将被索引)。
这些内置触发器的限制是它们一致对待所有输入列。为了处理不同列—比如, 为权重不同主体的标题—它有必要编写一个自定义触发器。 这是使用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 PROCEDURE messages_trigger();
记住当在触发器内部创造tsvector
值时,明确指定配置的名称是很重要的, 所以,该列的内容将通过改变default_text_search_config
而不会受到影响。 如果不这样做可能会导致诸如重载转储之后搜索结果改变的问题。
12.4.4. 收集文献统计
函数ts_stat
可用于检查你的配置和查找屏蔽候选词。
ts_stat(_sqlquery_ text, [ `_weights_` `text`, ]
OUT _word_ text, OUT _ndoc_ integer,
OUT _nentry_ integer) returns setof record
_sqlquery_
是一个包含返回单独tsvector
列的SQL查询的文本值。 ts_stat
执行查询并返回包含tsvector
数据的各个不同的语义(词)的统计。返回的列:
_word_
text
— 一个词的值_ndoc_
integer
—这个词出现的文档编号(tsvector
s)_nentry_
integer
—这个词出现的总数
如果提供_weights_
,仅仅计算这些权重之一。
例如,在一个文档集合中查找十个最常用的单词:
SELECT * FROM ts_stat('SELECT vector FROM apod')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;
同样的,但是只计算权重weight A
或者B
的单词:
SELECT * FROM ts_stat('SELECT vector FROM apod', 'ab')
ORDER BY nentry DESC, ndoc DESC, word
LIMIT 10;