问题报告 纠错本页面

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数据的各个不同的语义(词)的统计。返回的列:

如果提供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;