12.4. 其他功能#
本节介绍与文本搜索相关的其他函数和运算符。
12.4.1. 操作文档#
第 12.3.1 节展示了如何将原始文本文档转换为tsvector
值。PostgreSQL还提供了可用于操作已采用tsvector
形式的文档的函数和运算符。
-
tsvector
||tsvector
tsvector
连接运算符返回一个向量,该向量结合了作为参数给出的两个向量的词素和位置信息。位置和权重标签在连接期间保留。出现在右侧向量的词素将偏移左侧向量中提到的最大词素,因此结果几乎等同于对两个原始文档字符串的连接执行to_tsvector
的结果。(等价性不完全相同,因为从左侧参数的末尾删除的任何停用词不会影响结果,而如果使用文本连接,它们会影响右侧参数中词素的位置。)以向量形式使用连接而不是在应用
to_tsvector
之前连接文本的一个优点是,你可以使用不同的配置来解析文档的不同部分。此外,由于setweight
函数以相同的方式标记给定向量的所有词素,因此如果你想用不同的权重标记文档的不同部分,则在连接之前解析文本并执行setweight
是必要的。-
setweight(
vector
tsvector
,weight
"char"
) 返回tsvector
setweight
返回输入向量的副本,其中每个位置都已使用给定的weight
标记,即A
、B
、C
或D
。(D
是新向量的默认值,因此不会显示在输出中。)当连接向量时,这些标签会保留,从而允许对来自文档不同部分的单词使用排名函数赋予不同的权重。请注意,权重标签适用于位置,而不是词素。如果输入向量已剥离位置,则
setweight
不起作用。-
length(
vector
tsvector
) 返回integer
返回向量中存储的词素数。
-
strip(
vector
tsvector
) 返回tsvector
返回一个向量,其中列出了与给定向量相同的词素,但缺少任何位置或权重信息。结果通常比未剥离的向量小得多,但它也较不实用。相关性排名在未剥离的向量上不如在未剥离的向量上工作得那么好。此外,
<->
(FOLLOWED BY)tsquery
运算符永远不会匹配剥离的输入,因为它无法确定词素出现之间的距离。
有关tsvector
相关函数的完整列表,请参阅表 9.43。
12.4.2. 操作查询#
第 12.3.2 节展示了如何将原始文本查询转换为tsquery
值。PostgreSQL还提供了一些函数和运算符,可用于操作已经采用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(
query
tsquery
) 返回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
) 返回text
返回
tsquery
的一部分,该部分可用于搜索索引。此函数可用于检测不可索引的查询,例如仅包含停用词或仅包含否定词的查询。例如SELECT querytree(to_tsquery('defined')); querytree ----------- 'defin'
SELECT querytree(to_tsquery('!defined')); querytree
T
12.4.2.1. 查询重写#
ts_rewrite
系列函数搜索给定的tsquery
中目标子查询的出现,并用替代子查询替换每次出现。从本质上讲,此操作是tsquery
特定的子字符串替换版本。目标和替代组合可以被认为是一个查询重写规则。此类重写规则的集合可能是一个强大的搜索辅助工具。例如,您可以使用同义词(例如,new york
、big apple
、nyc
、gotham
)扩展搜索,或缩小搜索范围以将用户引导至某些热门话题。此功能与同义词词典(第 12.6.4 节)之间存在一些功能重叠。但是,您可以即时修改一组重写规则,而无需重新索引,而更新同义词库则需要重新索引才能生效。
ts_rewrite (
query
tsquery
,target
tsquery
,substitute
tsquery
) 返回tsquery
这种形式的
ts_rewrite
只应用一个重写规则:target
被substitute
替换,无论它出现在query
中的什么位置。例如SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery); ts_rewrite ------------ 'b' & 'c'
ts_rewrite (
query
tsquery
,select
text
) 返回tsquery
这种形式的
ts_rewrite
接受一个起始query
和一个 SQLselect
命令,该命令以文本字符串的形式给出。select
必须生成两列tsquery
类型的列。对于select
结果的每一行,第一列值(目标)的出现将被当前query
值中的第二列值(替代)替换。例如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'
12.4.3. 自动更新的触发器#
注意
本节中描述的方法已被存储生成列的使用方法所取代,如第 12.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 [, ... ])
这些触发器函数在CREATE TRIGGER
命令中指定的参数控制下,自动从一个或多个文本列计算tsvector
列。其使用示例为
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;
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
。这允许按行选择配置。其余参数是文本列(类型为text
、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
的更改影响。如果不这样做,很可能会导致问题,例如在转储和还原后搜索结果发生更改。
12.4.4. 收集文档统计信息#
函数ts_stat
可用于检查您的配置并查找停用词候选。
ts_stat(sqlquery text, [ weights text, ]
OUT word text, OUT ndoc integer,
OUT nentry integer) returns setof record
*sqlquery
*是包含 SQL 查询的文本值,该查询必须返回单个tsvector
列。ts_stat
执行查询并返回tsvector
数据中包含的每个不同词素(单词)的统计信息。返回的列是
word
text
— 词素的值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;