gpt4 book ai didi

sql - PostgreSQL全文搜索排名的最佳使用方法

转载 作者:行者123 更新时间:2023-11-29 11:13:42 25 4
gpt4 key购买 nike

this answer 开始我想知道使用 PostgreSQL 内置全文搜索的最佳方法是什么,如果我想按排名排序,并且限制为仅匹配查询。

让我们假设一个非常简单的表。

CREATE TABLE pictures (
id SERIAL PRIMARY KEY,
title varchar(300),
...
)

或者其他什么。现在我想搜索 title 字段。首先我创建一个索引:

CREATE INDEX pictures_title ON pictures 
USING gin(to_tsvector('english', title));

现在我想搜索'small dog'。这有效:

SELECT pictures.id, 
ts_rank_cd(
to_tsvector('english', pictures.title), 'small dog'
) AS score
FROM pictures
ORDER BY score DESC

但我真正想要的是:

SELECT pictures.id, 
ts_rank_cd(
to_tsvector('english', pictures.title), to_tsquery('small dog')
) AS score
FROM pictures
WHERE to_tsvector('english', pictures.title) @@ to_tsquery('small dog')
ORDER BY score DESC

或者这个(这不起作用 - 不能在 WHERE 子句中使用 score):

SELECT pictures.id, 
ts_rank_cd(
to_tsvector('english', pictures.title), to_tsquery('small dog')
) AS score
FROM pictures WHERE score > 0
ORDER BY score DESC

执行此操作的最佳方法是什么?我的问题有很多:

  1. 如果我使用带有重复 to_tsvector(...) 的版本,它会调用两次,还是它足够聪明以某种方式缓存结果?
  2. 有没有办法不用重复 to_ts... 函数调用就可以做到这一点?
  3. 有没有办法在 WHERE 子句中使用 score
  4. 如果有,按 score > 0 过滤还是使用 @@ 过滤更好?

最佳答案

@@ 运算符的使用将利用全文 GIN 索引,而 score > 0 的测试则不会。

我在问题中创建了一个表,但添加了一个名为 title_tsv 的列:

CREATE TABLE test_pictures (
id BIGSERIAL,
title text,
title_tsv tsvector
);

CREATE INDEX ix_pictures_title_tsv ON test_pictures
USING gin(title_tsv);

我用一些测试数据填充了表格:

INSERT INTO test_pictures(title, title_tsv)
SELECT T.data, to_tsvector(T.data)
FROM some_table T;

然后我用 explain analyze 运行之前接受的答案:

EXPLAIN ANALYZE 
SELECT score, id, title
FROM (
SELECT ts_rank_cd(P.title_tsv, to_tsquery('address & shipping')) AS score
,P.id
,P.title
FROM test_pictures as P
) S
WHERE score > 0
ORDER BY score DESC;

并得到以下内容。请注意 5,015 毫秒的执行时间

QUERY PLAN                                                                                                                                    |
----------------------------------------------------------------------------------------------------------------------------------------------|
Gather Merge (cost=274895.48..323298.03 rows=414850 width=60) (actual time=5010.844..5011.330 rows=1477 loops=1) |
Workers Planned: 2 |
Workers Launched: 2 |
-> Sort (cost=273895.46..274414.02 rows=207425 width=60) (actual time=4994.539..4994.555 rows=492 loops=3) |
Sort Key: (ts_rank_cd(p.title_tsv, to_tsquery('address & shipping'::text))) DESC |
Sort Method: quicksort Memory: 131kB |
-> Parallel Seq Scan on test_pictures p (cost=0.00..247776.02 rows=207425 width=60) (actual time=17.672..4993.997 rows=492 loops=3) |
Filter: (ts_rank_cd(title_tsv, to_tsquery('address & shipping'::text)) > '0'::double precision) |
Rows Removed by Filter: 497296 |
Planning time: 0.159 ms |
Execution time: 5015.664 ms |

现在将其与 @@ 运算符进行比较:

EXPLAIN ANALYZE
SELECT ts_rank_cd(to_tsvector(P.title), to_tsquery('address & shipping')) AS score
,P.id
,P.title
FROM test_pictures as P
WHERE P.title_tsv @@ to_tsquery('address & shipping')
ORDER BY score DESC;

结果以大约 29 毫秒的执行时间出现:

QUERY PLAN                                                                                                                                       |
-------------------------------------------------------------------------------------------------------------------------------------------------|
Gather Merge (cost=13884.42..14288.35 rows=3462 width=60) (actual time=26.472..26.942 rows=1477 loops=1) |
Workers Planned: 2 |
Workers Launched: 2 |
-> Sort (cost=12884.40..12888.73 rows=1731 width=60) (actual time=17.507..17.524 rows=492 loops=3) |
Sort Key: (ts_rank_cd(to_tsvector(title), to_tsquery('address & shipping'::text))) DESC |
Sort Method: quicksort Memory: 171kB |
-> Parallel Bitmap Heap Scan on test_pictures p (cost=72.45..12791.29 rows=1731 width=60) (actual time=1.781..17.268 rows=492 loops=3) |
Recheck Cond: (title_tsv @@ to_tsquery('address & shipping'::text)) |
Heap Blocks: exact=625 |
-> Bitmap Index Scan on ix_pictures_title_tsv (cost=0.00..71.41 rows=4155 width=0) (actual time=3.765..3.765 rows=1477 loops=1) |
Index Cond: (title_tsv @@ to_tsquery('address & shipping'::text)) |
Planning time: 0.214 ms |
Execution time: 28.995 ms |

正如您在执行计划中看到的,索引 ix_pictures_title_tsv 用于第二个查询,但不是在第一个查询中,使用 @@ 进行查询运算符(operator)的速度提高了惊人的 172 倍!

关于sql - PostgreSQL全文搜索排名的最佳使用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12933805/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com