sql - 在 PostgreSQL 中对多个唯一值进行排名的函数

标签 sql postgresql full-text-search unique ranking

我目前正在调整我的文本搜索查询以获得给定搜索词的最佳结果。我正在寻找的是一个排名功能,它只会提高搜索字段中新的唯一值的分数。它还应该比前缀命中更好地对精确命中进行评分。我能够通过庞大的查询获得所需的结果,但想知道您是否可以使用排名函数更优雅地获得类似的结果。我给你举个例子:

CREATE TABLE book (
  id BIGSERIAL NOT NULL PRIMARY KEY,
  title VARCHAR(255) NOT NULL
);

INSERT INTO book (title) VALUES ('Kate Mat');
INSERT INTO book (title) VALUES ('Kate Kate Mate');
INSERT INTO book (title) VALUES ('Cat Mat');

这是我使用搜索词“Kate”+“Mat”进行的大量查询:

SELECT
  title,
  a1 + a2 + b1 + b2 AS score
FROM (
       SELECT
         title,
         CASE WHEN to_tsvector('english', title) @@ to_tsquery('kate:*')
           THEN 1
         ELSE 0
         END AS a1,
         CASE WHEN to_tsvector('english', title) @@ to_tsquery('kate')
           THEN 0.5
         ELSE 0
         END AS a2,
         CASE WHEN to_tsvector('english', title) @@ to_tsquery('mat:*')
           THEN 1
         ELSE 0
         END AS b1,
         CASE WHEN to_tsvector('english', title) @@ to_tsquery('mat')
           THEN 0.5
         ELSE 0
         END AS b2
       FROM book
     ) scoredProducts
ORDER BY score DESC;

#----------------------results-------------------------
title           score
Kate Mat        3        -- exact hit for both terms
Kate Kate Mate  2.5      -- exact hit for 'Kate'. prefix hit for 'Mat'
Cat Mat         1.5      -- exact hit for 'Mat'

这其实就是我想看到的结果顺序。查询的明显问题是我需要为每个额外的搜索词调整它。我想要一个更像这样的语法:

SELECT
  title,
  ts_rank(to_tsvector('english', book.title), to_tsquery('kate:* | mat:*')) AS score
FROM book
ORDER BY score DESC;

#----------------------results-------------------------
title           score
Kate Kate Mate  0.0683918      -- prefix hits for both terms
Kate Mat        0.06079271     -- exact hit gets scored less
Cat Mat         0.030396355

遗憾的是,这并没有提供我想要的顺序,因为它对多个相同的匹配项的评分要高于精确的独特匹配项。是否可以编写这样的自定义排名函数?

最佳答案

我不太确定我是否理解你的问题,
您可以通过以下方式使用一些基本的 SQL 关键字和聚合函数来简化您的查询:

SELECT
  b.title,
  sum( case when to_tsvector('english' , title ) @@ to_tsquery(a.keyword)
            then a.score end ) AS score
  FROM book b
  cross join  ( 
     values
     ( 'kate:*', 1 ),
     ( 'kate', 0.5 ),
     ( 'mat:*', 1 ),
     ( 'mat', 0.5 )
) as a(keyword, score)
group by b.title
ORDER BY score DESC; 

您仍然需要为每个新的搜索词调整此查询,但现在看起来稍微容易一些。

关于sql - 在 PostgreSQL 中对多个唯一值进行排名的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41185157/

相关文章:

php - 需要MySQL数据结构建议

full-text-search - 重新索引后如何优雅地重启 Sphinx 搜索守护进程

c# - 使用 ROW_NUMBER() 和 PARTITION BY 的复杂 LINQ 查询的解决方案

python - 如何使用 SQLAlchemy 将关系对象数据插入数据库?

php - 字母顺序适用于姓氏但不适用于名字

mysql - 如何将1170101这样的日期格式转换为mysql日期格式2017-01-01?

postgresql - 与 postgreSQL 而不是 MongoDB 的 meteor react

mysql - 如何在数据库中搜索文本片段

java - 将java.sql.Timestamp转换为Java 8 ZonedDateTime吗?

php - SQL 加入收藏夹列表返回错误的名称