在这里发布了一个关于我如何提高SQL搜索方法速度的问题,我被建议更新我的表以使用全文搜索。这就是我现在所做的,使用Gist索引来加快搜索速度。在一些“普通”查询中,我注意到了一个显着的增长,我很高兴。
但是,我在搜索部分单词时遇到困难。例如,我有几个包含单词Squire(454)的记录,我有几个包含Squirrel(173)的记录。现在,如果我搜索Squire它只返回454条记录,但我也希望它返回Squirrel记录。
我的查询看起来像这样
SELECT title
FROM movies
WHERE vectors @@ to_tsoquery('squire');
我以为我可以做to_tsquery('squire%')
但这不起作用
如何让它搜索部分匹配?
另外,在我的数据库中,我有电影和其他只是电视节目的唱片。这些都是通过名称来区分,所以像“Munsters”是电视节目,而Munsters则是电影节目。我希望能够做的只是搜索电视节目和电影。关于如何实现这个目标的任何想法?
此致 Anthoni
答案 0 :(得分:47)
尝试,
SELECT title FROM movies WHERE to_tsvector(title) @@ to_tsquery('squire:*')
这适用于PostgreSQL 8.4+
答案 1 :(得分:30)
Anthoni,
假设您打算仅使用ASCII编码(可能很难,我知道),一个非常可行的选项可能是Trigram(pg_trgm)模块:http://www.postgresql.org/docs/9.0/interactive/pgtrgm.html
Trigram使用内置的索引方法,如Gist和Gin。您必须进行的唯一修改是在定义索引时,指定gist_trgm_ops
或gin_trgm_ops
的运算符类。
如果尚未安装contrib模块,在Ubuntu中就可以轻松地从shell运行以下命令:
# sudo apt-get install postgresql-contrib
使contrib模块可用后,必须将pg_trgm扩展名安装到相关数据库中。您可以通过在要安装模块的数据库上执行以下PostgreSQL查询来执行此操作:
CREATE EXTENSION pg_trgm;
安装pg_trgm扩展程序后,我们已经准备好了!
-- Create a test table.
CREATE TABLE test (my_column text)
-- Create a Trigram index.
CREATE INDEX test_my_colun_trgm_idx ON test USING gist (my_column gist_trgm_ops);
-- Add a couple records
INSERT INTO test (my_Column) VALUES ('First Entry'), ('Second Entry'), ('Third Entry')
-- Query using our new index --
SELECT my_column, similarity(my_column, 'Frist Entry') AS similarity FROM test WHERE my_column % 'Frist Entry' ORDER BY similarity DESC
答案 2 :(得分:5)
即使使用LIKE
,你也无法从squire%
获得“松鼠”,因为“松鼠”有两个'r'。要获得Squire和Squirrel,您可以运行以下查询:
SELECT title FROM movies WHERE vectors @@ to_tsquery('squire|squirrel');
要区分电影和电视节目,您应该在数据库中添加一列。然而,有很多方法可以给这只猫皮肤。您可以使用子查询强制postgres首先找到匹配'squire'和'squirrel'的电影,然后搜索该子集以查找以'“'开头的标题。可以创建索引以供{{ 1}}搜索。
如果没有探索其他索引的可能性,你也可以运行它们 - 搞乱它们以找到最快的:
LIKE '"%...'
或
SELECT title
FROM (
SELECT *
FROM movies
WHERE vectors @@ to_tsquery('squire|squirrel')
) t
WHERE title ILIKE '"%';
答案 3 :(得分:5)
@ alexander-mera解决方案效果很棒!
注意:还要确保将空格转换为+
。例如,如果您要搜索squire knight
。
SELECT title FROM movies WHERE to_tsvector(title) @@ to_tsquery('squire+knight:*')
答案 4 :(得分:2)
对此的广泛解决方案是使用PG的ts_rewrite函数来设置适用于备用匹配的别名表(请参阅Query Rewriting)。这包括与您相同的案例,同时还处理完全不同的案例,例如搜索tree rat
并获取squirrel
的结果等。
该链接的完整详细信息和说明,但其要点是您可以设置包含2个ts_query列的别名表,并将该表的查询传递给您的搜索,如下所示:
CREATE TABLE aliases (t tsquery primary key, s tsquery);
INSERT INTO aliases VALUES(to_tsquery('supernovae'), to_tsquery('supernovae|sn'));
SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
导致最终查询看起来更像:
WHERE vectors @@ ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases')
这类似于PG中的词库设置,但每次添加内容时都不需要完整的重新索引。当你遇到很少的拼写变化和“当我搜索这个时我希望这样的结果”的情况下,很容易将它们快速地添加到表中。您可以向该表添加更多列,只要基于ts_rewrite
的查询返回2个预期to_tsquery
列。
当您深入了解该文档时,您还会看到性能调优的建议示例。在使用trigram进行纯粹速度和使用向量/查询/重写进行稳健性之间存在平衡。
答案 5 :(得分:0)
可能有用的一件事就是将你要搜索的单词分成更小的部分。所以你可以找到有squi或quir或squire等的东西......我不确定它会有多高效,但它可能有所帮助。
当您搜索电影或电影时,您可以尝试将文字放在单引号中。所以它可能是'show'或'show“'。我认为这也可行。