如何设置tsquery
的权重?我需要为从tsquery
获得的plainto_tsquery
设置一个权重。
有可能吗?类似于setweight(plainto_tsquery(''), 'A')
,但它只适用于tsvector
。
最佳答案
我也有这个问题。我的用例是大型文档、许多部分,我希望提供“仅搜索标题文本”的选项。(标题的权重为A,分散在整个文档中;其他部分的权重为B、C或D,具体取决于标题出现的位置。)
这里有两个解决方案应该会有帮助。
解决方案1:tsquery的setweight函数
函数将tsquery转换为文本,应用正则表达式设置权重,然后转换回tsquery。
CREATE FUNCTION setweight(query tsquery, weights text) RETURNS tsquery AS $$
SELECT regexp_replace(
query::text,
'(?<=[^ !])'':?(\*?)A?B?C?D?', ''':\1'||weights,
'g'
)::tsquery;
$$ LANGUAGE SQL IMMUTABLE;
例子:
select setweight( plainto_tsquery('fat cats and rats'), 'A' );
-- 'fat':A & 'cat':A & 'rat':A
select setweight( phraseto_tsquery('fat cats and rats'), 'A' );
-- 'fat':A <-> 'cat':A <2> 'rat':A
select setweight( to_tsquery('fat & (cat:A & rat) & !dog:*CD'), 'BC' );
-- 'fat':BC & 'cat':BC & 'rat':BC & !'dog':*BC
解决方案2:基于过滤tsvector的函数索引
首先在要搜索的全文本列上创建其他索引。
例如
CREATE INDEX fulltext_idx
ON your_table USING gin
(fulltext)
CREATE INDEX fulltext_idx_A
ON your_table USING gin
(ts_filter(fulltext, '{a}'))
CREATE INDEX fulltext_idx_AB
ON your_table USING gin
(ts_filter(fulltext, '{a,b}'))
无论你需要什么重量组合。
然后,在搜索时,使用过滤表达式。例如。:
SELECT *
FROM your_table
WHERE ts_filter(fulltext, '{a}') @@ plainto_tsquery('your query')
搜索应该在索引表达式上进行。
讨论
解决方案1提供了您正在寻找的函数,但是加权查询的问题是,尽管postgres将使用索引来查找候选匹配项,但它仍然需要拉回到每个文档来检查权重。
在我的例子中,当只按标题搜索时,解决方案2似乎提供了更好的性能。标题中的文本(权重A)使用的词汇表比整个文档中的词汇表小得多,因此全文比全文小得多,匹配后不需要重新检查结果。
对于您自己的情况,性能将完全取决于您自己的文档结构和查询的性质,因此使用“explain analyze”进行测试以选择更好的解决方案。考虑到你的年龄,我想你已经解决了这个问题:-)
注:
ts_filter()
和phraseto_tsquery()
来自Postgres9.6。关于postgresql - PostgreSQL:如何为tsquery设置权重,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42767638/