此部分描述了一些与文本搜索相关的有用函数和运算符。
第 12.3.1 节 说明了如何将原始文本文档转换成 tsvector
值。PostgreSQL 同时提供了有关已用 tsvector
形式表示的文档的操作函数和运算符。
tsvector
|| tsvector
tsvector
连接运算符返回一个矢量,其中包含作为参数给出时两矢量的词素和位置信息。位置和权重标签在连接中将得到保留。在右手矢量中出现的词素位置将由左手矢量中提到过的最长的位置抵消,因此,结果与对两个原始文档字符串连接后的 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
返回一个列出向量中相同词素的向量,但它没有位置或权重信息。 与未提取的向量相比,结果通常小得多,但它也较不有用。 重要性排名对于提取向量来说不如未提取向量好。 此外,<->
(后面加)tsquery
运算符永远无法匹配提取的输入,因为它无法确定词素出现之间的距离。
表 9.43 中提供了 tsvector
相关函数的完整列表。
第 12.3.2 节 展示了如何将原始的文本查询转换为 tsquery
值。 PostgreSQL 也提供了可用来操作已经采用 tsquery
形式的查询的函数和运算符。
tsquery
&& tsquery
返回给定两个查询的 AND 组合。
tsquery
|| tsquery
返回给定两个查询的 OR 组合。
!! tsquery
返回给定查询的否定(NOT)。
tsquery
<-> tsquery
返回一个查询,用于搜索与第一个给定查询匹配,且紧跟着与第二个给定查询匹配的内容,使用 <->
(后面加)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
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
出现于 query
的何处,都被 substitute
替换。例如
SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery); ts_rewrite ------------ 'b' & 'c'
ts_rewrite (query
tsquery
, select
text
) 返回 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'
请注意,当通过这种方式应用多条重写规则时,应用顺序可能重要;因此,在实践中,您会希望源查询按某个排序键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.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
更改的影响。如果不这样做,很可能会导致问题,例如在转储和还原之后搜索结果发生更改。
函数 ts_stat
对于检查配置和查找停用词候选很有用。
ts_stat(sqlquery
text
, [weights
text
, ] OUTword
text
, OUTndoc
integer
, OUTnentry
integer
) returnssetof 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;