【问题标题】:keyset pagination with full text search on postgresql在 postgresql 上进行全文搜索的键集分页
【发布时间】:2020-02-09 01:36:52
【问题描述】:

我有一个包含 +100,000 条记录的“用户”表。我想开始使用键集分页来加快获取记录的过程。

以下查询有效。此查询获取记录集的第二页(从 user_id: 1001 开始,一直到 user_id: 2000)。

SELECT
    user_id,
    username
FROM
    users
WHERE
    user_id > 1000
ORDER BY
    user_id ASC
LIMIT
    1000

问题是:我不想对 user_id 上的记录进行排序。我有一个名为“tokens”的列,它是一个 to_tsvector 列。我想对记录集执行全文搜索并对用户进行排序。新查询:

SELECT
    user_id,
    username,
    to_tsrank(tokens, plainto_tsquery('search query')) AS rank
FROM
    users
WHERE
    tokens @@ plainto_tsquery('search query')

如何在第二个查询上应用键集分页,以便结果按排名而不是 user_id 排序?

重要:

我试过这个,但这不起作用!

SELECT
    user_id,
    username,
    to_tsrank(tokens, plainto_tsquery('search query')) AS rank
FROM
    users
WHERE
    tokens @@ plainto_tsquery('search query')
AND
    to_tsrank(tokens, plainto_tsquery('search query')) < $1 // $1 = last fetched rank
ORDER BY
    rank DESC
LIMIT
    1000

假设当结果按“排名”进行排名时,第 1,000 个结果的排名为 0.5。 $1(最后获取的排名)将是 0.5,所以我会选择排名 相同排名。因此,如果第 1,001 条记录也是 rank = 0.5,则不会获取它,因为我在查询中说 rank &lt; 0.5。我也不能说rank &lt;= 0.5,因为这会再次获取rank = 0.5 的先前结果。

有人知道这个问题的解决方法吗?

【问题讨论】:

    标签: postgresql full-text-search


    【解决方案1】:

    您必须提供完全确定的 ORDER BY。假设 user_id 是唯一的:

    ORDER BY rank desc, user_id
    

    那么你的 WHERE 将包括:

    AND (rank < :last_rank or (rank = :last_rank and user_id > :last_user_id))
    

    但这不会有效率,所以你还不如只做OFFSET。

    更好的是,根本不要这样做。没有人会真正阅读 1000 个结果,然后想“你知道,我想再做几次”。唯一会这样做的是网络爬虫,网络爬虫这样做的唯一原因是因为它是您提供的唯一方法。只要让他们设置一个他们想要的上限,并且不提供分页。

    【讨论】:

    • 也许你是对的。这是一个应用程序,用户可以搜索其他用户。当他们输入一些文本时,与文本最匹配的用户名将首先出现。如果有多个结果,则最受欢迎的用户必须排在第一位。我认为大多数人不会向下滚动到 50 多个结果。感谢您的意见!
    猜你喜欢
    • 2014-07-07
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-31
    • 1970-01-01
    相关资源
    最近更新 更多