有没有办法在PostgreSQL中“扩展” ts_rank
函数或创建自定义setweight
?
我有2个表,records
和tags
,records
可以有多个标签。使用表records_tags
的多对多关联。 records_tags
的列score
表示同一标签的得分对每条记录都是不同的,并且在PostgreSQL的setweight中,权重可用的级别不仅仅是4个。
简化数据示例:
records
表
id | title | description
----+------------------------+--------------------------------------
1 | 'The best record ever' | 'Long and meaningful description...'
2 | 'Another record' | 'Description of the other record...'
tags
表
id | name
----+---------------------------
1 | 'artificial intelligence'
2 | 'machine learning'
3 | 'life science'
records_tags
表
record_id | tag_id | score
-----------+--------+-------
1 | 1 | 87
1 | 2 | 23
2 | 1 | 54
2 | 2 | 67
2 | 3 | 90
这些表中的数据合并到另一个表search_documents
中,该表具有列body
作为jsonb类型,并包括每个记录的聚集标记名。
search_documents.body
看起来像这样:
{
title: 'The best record ever',
description: 'Long and meaningful description...',
tags: ['artificial intelligence', 'machine learning']
}
现在,我已经使用tsvector和setweight实现了全文搜索,如下所示:
setweight(to_tsvector('simple', (body ->> 'tags')), 'A') || ' ' ||
setweight(to_tsvector('english', (body ->> 'title')), 'B') || ' ' ||
setweight(to_tsvector('english', (body ->> 'description')), 'C')
以及类似的搜索查询:
SELECT
ts_rank(sd.tsv, to_tsquery('english', ''' ' || :query || ' ''' || ':*'), 1) +
ts_rank(sd.tsv, to_tsquery('simple', ''' ' || :query || ' ''' || ':*'), 1) AS rank
sd.id AS id
FROM
search_documents sd
WHERE
sd.tsv @@ to_tsquery('english', ''' ' || :query || ' ''' || ':*') OR
sd.tsv @@ to_tsquery('simple', ''' ' || :query || ' ''' || ':*')
但是它完全不允许我使用标签的分数。在计算score
时,除了此以外,还有什么方法可以使用标签的rank
吗?将records_tags.score
也包括在search_documents.body
中也不是问题,因为每个记录的内容都不同。
您可以使用setweight的3个参数形式来设置特定词素的权重,而不是将整个tsvector的所有权重设置为相同。大概您会将其内置到表“ search_documents”的创建过程中,但是由于您没有向我们展示该创建过程,因此我无法建议具体的实现。一旦有了正确加权的tsvector,就可以将其存储为单独的列,而不是存储在JSONB中。