PostgreSQL文本搜索:如何按ts_vector词位索引排序结果
问题描述
开发带自动补全功能的搜索栏时,已使用simple字典将displayname列转换为ts_vector类型的document列,当前document列数据如下:
"'rami':1 'morgan':2" "'serena':1 'william':2" "'ferrel':2" "'dicaprio':2 'ronald':1"
执行查询语句:
select displayname from celeb where document @@ to_tsquery('simple', 'r:*')
返回结果不符合预期,需求是按词位索引1(名字)优先排序——查询r:*时,名字以r开头的结果排在姓氏以r开头的结果之前,不清楚如何基于ts_vector的词位索引实现排序。
解决方案
可以通过两种方式实现基于ts_vector词位索引的排序:
方法一:直接指定词位匹配排序
利用ts_query的词位限定语法(:数字),判断匹配的词是否位于位置1,以此作为排序依据:
SELECT displayname FROM celeb WHERE document @@ to_tsquery('simple', 'r:*') ORDER BY -- 位置1匹配的结果排前面 CASE WHEN document @@ to_tsquery('simple', 'r:*:1') THEN 0 ELSE 1 END, -- 可选:按displayname二次排序 displayname;
这里r:*:1表示匹配位置1中以r开头的词,通过CASE语句将这类结果的排序权重设为0,其他设为1,实现优先排序。
方法二:拆分ts_vector提取词位排序
将ts_vector拆分为独立的词和位置数组,提取匹配词的位置后排序:
SELECT c.displayname FROM celeb c, unnest(c.document) AS t(lexeme, positions) WHERE t.lexeme LIKE 'r%' GROUP BY c.displayname, c.document ORDER BY -- 优先展示包含位置1的结果 BOOL_OR(1 = ANY(t.positions)) DESC, -- 可选:按displayname二次排序 displayname;
unnest(c.document)会把ts_vector拆分成每行一个词和对应的位置数组,通过1 = ANY(t.positions)判断该词是否在位置1,用BOOL_OR聚合后倒序排序,让包含位置1匹配的结果排在前面。
内容的提问来源于stack exchange,提问作者Muathcs
相关产品推荐
相关产品推荐

