分类:
2008-05-21 15:11:12
|
本节描述在文本搜索里有用的附加的函数和操作符。
一节显示了裸文本文档如何转换成 tsvector 值。PostgreSQL 还提供了可以用于操作已经是 tsvector 形式的文档的函数。
tsvector || tsvector
setweight(vector tsvector, weight "char") returns tsvector
length(vector tsvector) returns integer
strip(vector tsvector) returns tsvector
节显示了裸文本查询如何转换成 tsquery 值。PostgreSQL 还提供了可以用于操作已经是 tsquery 形式的查询的函数和操作符。
tsquery && tsquery
tsquery || tsquery
!! tsquery
numnode(query tsquery) returns integer
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
SELECT querytree(to_tsquery('!defined')); querytree -----------
ts_rewrite 族函数搜索一个特定的 tsquery 以获取一个目标子查询是否出现,然后把每个出现都替换成其它的子查询。实际上这个操作是一个tsquery 版本的子字串替换。目标和替换的组合可以认为是一个重写规则。一组这样的重写规则可以成为搜索的强力助手。比如,你可以适用同义词扩展搜索(比如,new york,big apple,nyc,goham)或者把搜索限制起来,把用户导向一些热点主体。这个函数和知识词典(的功能之间有一些重叠。不过,你可以运行时修改一个重写规则集而不用重建索引,而更新知识词典需要重建索引才能生效。
ts_rewrite (query tsquery, target tsquery, substitute tsquery) returns tsquery
SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery); ts_rewrite ------------ 'b' & 'c'
ts_rewrite (query tsquery, select text) returns tsquery
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'
让我们看看一个真实的宇航搜索的例子。我们会对查询 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。这样就允许我们可以针对不同行使用不同的配置。剩下的参数是文本字段的名称(类型是 text,varchar 或者 char)。这些将被以给出的顺序包含在文档中。NULL 值会被忽略(但是其它字段仍将被索引)。
内置的触发器的一个限制是它们把所有输入字段都看成是一样的。要想用不同方式处理字段 -- 比如,给 body 赋予不同的权重 -- 我们就需要书写一个客户化的触发器。下面是一个使用 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 是一个文本值,包含一个 SQL 查询,它必须返回单个 tsvector 字段。ts_stat 执行这个查询并返回包含在这个 tsvector 数据里有关每个独立的语意(lexeme)(单词)的统计,返回的字段有
如果提供了权重,那么只计算包含该权重的词。
比如,在文档里找出十个最常见的词:
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;