首页 >web前端 >js教程 >PostgreSQL 全文搜索按位置排名

PostgreSQL 全文搜索按位置排名

Patricia Arquette
Patricia Arquette原创
2024-12-13 13:08:10968浏览

PostgreSQL Full Text Search Rank by Position

最近,我遇到了全文搜索的问题。我在搜索输入中使用此功能,后端会在您键入时发送可能匹配的提示。后端数据库是PostgreSQL。我需要根据搜索词在文本中的位置对提示进行排名。

因此,如果您搜索“星球大战”标题,您将首先看到“星球大战”帖子,而不是“星球大战 7-9 如何改变星球大战世界(一部关于星球大战的有趣制作的纪录片)”,这可能会该词出现 3 次后排名更高。

PostgreSQL 中的全文搜索

PostgreSQL 中的全文搜索可以很容易地实现。主要使用两个工具:

  • tsvector - 表示可搜索文档。
  • tsquery - 表示针对文档执行的搜索查询。

假设我们要搜索博客文章的标题。为了使它们可搜索,我们可以使用以下查询:

SELECT 
id, 
title 
FROM blogposts
WHERE to_tsquery('JavaScript') @@ to_tsvector(posts.title);

在这种情况下,我们会在每次搜索时动态地将帖子标题转换为 tsvector。然而,这种转变需要一些时间。更好的方法是提前在数据库中执行此转换,并将其存储为标题的索引,以便更快地搜索。

让我们创建一个新的标题向量列,并为这个新列建立索引:

ALTER TABLE blogposts ADD COLUMN search_vector tsvector;
UPDATE blogposts SET search_vector = (to_tsvector(posts.title));
CREATE INDEX titles_fts_idx ON blogposts USING gin(search_vector);

现在尝试搜索术语“JavaScript”

SELECT 
id, 
title
FROM blogposts
WHERE to_tsquery('JavaScript') @@ search_vector;

您还可以直接在标题列上从 ts 向量创建索引,如下所示:

CREATE INDEX titles_fts_idx ON blogposts USING GIN (to_tsvector(posts.title));

并使用这样的搜索:

SELECT 
id, 
title
FROM blogposts
WHERE to_tsquery('JavaScript') @@ posts.title;

现在,全文搜索将非常快,只需几毫秒即可完成。

对结果进行排名

PostgreSQL 提供了 ts_rank 功能,它允许您对搜索结果进行评分并根据排名对其进行排序。 PostgreSQL 支持以下排名选项:

  • 0(默认值)忽略文档长度
  • 1 将排名除以 1 文档长度的对数
  • 2 将排名除以文档长度
  • 4 将排名除以范围之间的平均调和距离(这仅由 ts_rank_cd 实现)
  • 8 将排名除以文档中唯一单词的数量
  • 16 将排名除以 1,即文档中唯一单词数量的对数
  • 32 将排名除以 1

您可以像这样使用 ts_rank:

SELECT
    ...
ts_rank(search_vector, to_tsquery('JavaScript'), 0) as rank_title
    ...
ORDER BY rank_title DESC NULLS LAST

但是,没有基于搜索词在字符串中的位置(即标题列)的内置排名选项。

救援位置

幸运的是 PostgreSQL 中有 POSITION 函数。 PostgreSQL POSITION 函数用于查找给定字符串中子字符串的位置。在我们的例子中,我们可以像这样使用它

SELECT 
id, 
title 
FROM blogposts
WHERE to_tsquery('JavaScript') @@ to_tsvector(posts.title);

ts_rank 使用归一化整数 2,因为 2 将排名除以文档长度
神奇数字 0.0001 是为了避免除以 0,因为 POSTION 函数从 1 开始计数,而不是从 0 开始计数,如果未找到字符串,则返回 0。

最终代码可能如下所示:

ALTER TABLE blogposts ADD COLUMN search_vector tsvector;
UPDATE blogposts SET search_vector = (to_tsvector(posts.title));
CREATE INDEX titles_fts_idx ON blogposts USING gin(search_vector);

搜索更多术语

如果您一次搜索多个术语(例如 JavaScriptTypeScript),则必须提及一个警告。

to_tsquery 函数的参数可以非常灵活地使用,包括逻辑运算符等。另一方面,POSITION 函数“只是”字符串中的一个子字符串。

现实世界的例子

这是我在 SvelteKit Web 应用程序中来自现实世界端点的示例,该应用程序使用 postgres (sql) npm 库:

SELECT 
id, 
title
FROM blogposts
WHERE to_tsquery('JavaScript') @@ search_vector;

以下是相关文档的链接:

  • https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-DOCUMENTS
  • https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING
  • https://www.postgresql.org/docs/9.1/functions-string.html

以上是PostgreSQL 全文搜索按位置排名的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn