On this page
12.4. 其他功能
本节介绍在文本搜索中有用的其他功能和运算符。
12 .4.1. 处理文件
Section 12.3.1显示了如何将原始文本文档转换为tsvector
值。 PostgreSQL 还提供了可用于处理tsvector
形式的文档的函数和运算符。
-
tsvector
串联运算符返回一个向量,该向量结合了作为参数给出的两个向量的词素和位置信息。在连接过程中保留位置和重量标签。出现在右侧向量中的位置偏移了左侧向量中提到的最大位置,因此结果几乎等于对两个原始文档字符串的串联执行to_tsvector
的结果。 (等价关系并不精确,因为从左手参数末尾删除的任何停用词都不会影响结果,而如果使用文本串联,它们会影响右手参数中词素的位置.)
在矢量形式中使用串联而不是在应用to_tsvector
之前串联文本的一个优点是,您可以使用不同的配置来解析文档的不同部分。同样,由于setweight
函数以相同的方式标记给定向量的所有词素,因此如果要使用不同的权重标记文档的不同部分,则必须在连接之前分析文本并执行setweight
。
setweight(vector tsvector, weight "char") returns tsvector
setweight
返回 Importing 向量的副本,其中每个位置都已用给定的*weight
*(A
,B
,C
或D
)标记。 (D
是新向量的默认值,因此不会在输出中显示.)将向量连接在一起时将保留这些标签,从而允许通过排序功能对来自文档不同部分的单词进行不同的加权。
请注意,权重标签适用于位置,不适用于词缀。如果 Importing 向量已去除位置,则setweight
不执行任何操作。
length(vector tsvector) returns integer
- 返回向量中存储的词素数。
strip(vector tsvector) returns tsvector
- 返回一个列出与给定向量相同的词素的向量,但缺少任何位置或权重信息。结果通常比未剥离的矢量小得多,但它的用处也较小。相关度排序在未剥离向量上的效果不如未剥离向量。同样,
<->
(FOLLOWED BY)tsquery
运算符将永远不会匹配剥离的 Importing,因为它无法确定词素出现之间的距离。
- 返回一个列出与给定向量相同的词素的向量,但缺少任何位置或权重信息。结果通常比未剥离的矢量小得多,但它的用处也较小。相关度排序在未剥离向量上的效果不如未剥离向量。同样,
Table 9.41提供了与tsvector
相关的功能的完整列表。
12 .4.2. 操纵查询
Section 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' | 'fat' <-> 'rat'
tsquery_phrase(query1 tsquery, query2 tsquery [, distance integer ]) returns tsquery
- 返回一个查询,该查询使用
<N>
tsquery
运算符搜索与第一个给定查询的匹配项,然后搜索与第二个给定查询的匹配项,它们的距离为*distance
*词素。例如:
- 返回一个查询,该查询使用
SELECT tsquery_phrase(to_tsquery('fat'), to_tsquery('cat'), 10);
tsquery_phrase
------------------
'fat' <10> 'cat'
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
SELECT querytree(to_tsquery('!defined'));
querytree
-----------
12 .4.2.1. 查询 Rewrite
ts_rewrite
系列函数在给定的tsquery
中搜索目标子查询的出现,并用替代子查询替换每个出现。本质上,此操作是tsquery
特定版本的子字符串替换。目标和替代组合可以视为查询重写规则。此类重写规则的集合可能是强大的搜索帮助。例如,您可以使用同义词(例如new york
,big apple
,nyc
,gotham
)扩展搜索范围,或缩小搜索范围以将用户引导至某个热门 Topic。此功能和同义词词典(Section 12.6.4)在功能上有一些重叠。但是,您可以即时修改一组重写规则而无需重新编制索引,而更新同义词库需要重新编制索引才能有效。
ts_rewrite (query tsquery, target tsquery, substitute tsquery) returns 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) returns tsquery
- 这种形式的
ts_rewrite
接受起始*query
*和 SQL *select
*命令,该命令以文本字符串形式给出。 *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'
请注意,以这种方式应用多个重写规则时,应用的 Sequences 可能很重要。因此在实践中,您将希望源查询ORDER BY
一些 Order 密钥。
让我们考虑一个真实的天文学例子。我们将使用表驱动的重写规则来扩展查询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 [, ... ])
这些触发函数在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
)。这些将按照给定的 Sequences 包含在文档中。 NULL 值将被跳过(但其他列仍将被索引)。
这些内置触发器的局限性在于它们对所有 Importing 列的处理方式相同。要以不同方式处理列(例如,以不同的方式称呼标题),必须编写自定义触发器。这是一个使用 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
-lexeme 的值
-
ndoc
*integer
-单词出现的文档数(tsvector
s)
-
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;