PostgreSQL 9.3.1 中文手册 | ||||
---|---|---|---|---|
上一页 | 上一级 | 章 12. 全文检索 | 下一页 |
本节描述了连接文本搜索中有用的附加功能和操作符。
节第 12.3.1 节显示了原始文本文档如何转换成tsvector值。 PostgreSQL也提供用于操作已经在tsvector形式中的文档的函数和操作符。
tsvector连接操作符返回一个连接词的向量,以及作为参数给定的2个向量的位置信息。
在连接期间重新获得位置和权重标签。出现在右边向量位置通过左边向量提到的最大位置相抵消,
因此这个结果几乎等同于2个原始文档字符串连接中执行to_tsvector
的结果。(这个等价是不准确的,
因为任何从左边参数中删除的干扰词不会影响结果,然而,如果使用文本连接,它们影响右边参数词的位置)。
使用级联中的向量形式而不是在应用to_tsvector
之前连接文本的一个优势是,
你可以使用不同的配置解析文档的不同部分。同时,由于setweight
函数标记所有相同方式给定向量的词汇,
解析文本是必要的,并且如果你想用不同的权重标记文档不同部分,连接前做setweight
。
setweight
返回一个输入向量的拷贝,其中每一个位置用给定的weight,
A, B, C或者
D之一进行标记。(D是缺省新向量,因此不显示在输出上。)当向量连接时,保留这些标签,
允许一个文档的不同部分的词通过不同相关函数加权。
注意权重标签适用于位置,不是词汇。如果输入向量已经被剥夺了位置,则setweight
不做任何事情。
返回存储在向量中的词的数量。
返回一个向量,其中列出了给定向量的同一词,但它缺乏任何位置和权重信息。 虽然为相关性排序返回的向量比一个未拆分向量用处少,它通常会小得多。
节第 12.3.2 节显示了原始文本查询如何转换成tsquery值。 PostgreSQL也提供了函数和操作符用于处理已存在tsquery形式中的查询
返回两个给定查询的与组合。
返回两个给定查询的或组合。
返回给定查询的反面(非)。
返回在一个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
返回可用于搜索索引的tsquery部分。此函数对检测未索引查询是有帮助的,例如那些只包含干扰词或否定术语。比如:
SELECT querytree(to_tsquery('!defined')); querytree -----------
函数族ts_rewrite
搜索一个特定的目标查询事件tsquery,和替换每个替代子查询。
实际上这个操作是一个子字符串替换的tsquery-特定版本。目标和替换组合可以被认为是一个查询重写规则。
一组这样的重写规则可以是一个强大的搜索帮助。例如,你可以使用同义词扩大搜索(例如,new york, big apple, nyc,
gotham)或缩小搜索一些热点问题的直接用户。在这些特性和同义词词典之间功能上有一些重叠(节第 12.6.4 节)。然而,
你可以在不重建索引情况下即时修改重写规则,而更新词库需要重建索引才能有效。
ts_rewrite
的这种形式只适用于一个单一的重写规则:无论出现在query的什么地方,target通过substitute替换。比如:
SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery); ts_rewrite ------------ 'b' & 'c'
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'
当使用单独的列存储文档的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而不会受到影响。 如果不这样做可能会导致诸如重载转储之后搜索结果改变的问题。
函数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 —这个词出现的文档编号(tsvectors)
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;