2010-03-25 111 views
11

在这里发布一个关于如何提高我的SQL搜索方法的速度的问题之后,我被建议更新我的表以利用全文搜索。这就是我现在所做的,使用Gist索引来加快搜索速度。在一些“简单”的查询中,我注意到了一个显着的增加,我很高兴。PostgreSQL:全文搜索 - 如何搜索部分单词?

但是,我很难搜索部分单词。例如,我有几个包含Squire(454)的记录,而且我有几个包含Squirrel(173)的记录。现在,如果我搜索Squire,它只会返回454条记录,但我也希望它可以返回Squirrel记录。

我的查询看起来像这样

SELECT title 
FROM movies 
WHERE vectors @@ to_tsoquery('squire'); 

我想我能做到to_tsquery('squire%'),但不起作用。
如何获得它以搜索部分匹配?

此外,在我的数据库中,我有记录是电影和其他只是电视节目。这些名称与名称不同,因此“明斯特”是电视节目,而明斯特是该节目的电影。我想要做的就是只搜索电视节目和电影。有关我如何实现这一点的任何想法?

问候 Anthoni

+0

如果你有'squire'这个搜索键,但是想得到'squirrel'的结果,你可能需要指定其他的约束条件。因为否则的话,人们可能会说他们有搜索键“妈妈”,但想要结果“兔子”。所以也许你可能想要分割你的搜索键并把'squire'变成'|' sq | squ | squi | squir |乡绅......这个或更有趣的算法会让你成为'松鼠'。我认为@Joshua Burns的答案包含比我更通用的解决方案,但如果你想要通用。 – 2015-09-17 08:12:46

回答

4

即使使用LIKE你将无法从squire%得到“松鼠”,因为“松鼠”有两个“R的。要获得乡绅和松鼠,你可以运行下面的查询:

SELECT title FROM movies WHERE vectors @@ to_tsquery('squire|squirrel'); 

电影和电视之间的区别展示了应该列添加到您的数据库。但是,这种猫的皮肤有很多种方法。您可以使用子查询来强制postgres首先找到匹配'squire'和'squirrel'的电影,然后搜索该子集以查找以'''开头的标题。可以创建索引以便在LIKE '"%...'搜索中使用。

SELECT title 
FROM (
    SELECT * 
    FROM movies 
    WHERE vectors @@ to_tsquery('squire|squirrel') 
) t 
WHERE title ILIKE '"%'; 

可能工作
SELECT title 
FROM movies 
WHERE vectors @@ to_tsquery('squire|squirrel') 
    AND title ILIKE '"%'; 
0

一件事是打破了一句话:围绕与他们乱找这是最快的 -

不考察其他索引可能你也可以运行这些你正在寻找更小的p艺术。所以,你可以寻找那些拥有squi或quir或者乡绅等等的东西......我不确定它的效率如何,但它可能会有所帮助。

当您搜索电影或电影时,您可以尝试将文本放在单引号中。所以它可以是'show'或者'show''。我认为这也可以发挥作用。

27

尝试,

SELECT title FROM movies WHERE to_tsvector(title) @@ to_tsquery('squire:*') 

这适用于PostgreSQL的8。4+

+2

你已经指定了一个前缀匹配的词位,但它不会解决问题:它仍然缺少'r'。你应该删掉这个答案。 – 2013-02-11 00:10:10

+2

@RichardMichael我不同意,因为这种方法的作品。 OP正试图获得两个不相似的单词。 “乡绅”不是**“松鼠”一词的一部分。他要求部分匹配,这个答案就是这样。它应该是upvoted。 – 2016-09-06 08:27:04

+0

感谢您的支持,我在一个用例中提供帮助。 +1 – 2017-11-23 04:48:59

25

Anthoni,

假设你打算只使用ASCII编码(可能是困难的,我知道),一个非常可行的办法可能是巽(pg_trgm)模块:http://www.postgresql.org/docs/9.0/interactive/pgtrgm.html

八卦利用Gist和Gin等内置索引方法。您必须进行的唯一修改是在定义索引时指定gist_trgm_opsgin_trgm_ops的运营商类别。

如果尚未安装的contrib模块,在Ubuntu它一样方便,运行在shell下面的命令:

# sudo apt-get install postgresql-contrib 

于contrib模块之后可用,您必须安装pg_trgm拓成有问题的数据库。您可以通过在数据库上执行下面的PostgreSQL的查询您希望将模块安装到这样做:在pg_trgm延长已安装

CREATE EXTENSION 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

为什么这不是公认的答案?是最好的:) – jperelli 2012-05-06 21:31:26

+0

在你的例子中的相似性使用完美的单词,而不是你的where子句中使用的拼写错误的单词。选择相似性('Frist Entry','First Entry')=> 0.5 – 2012-11-27 10:39:42

+0

好点,我的错字。解决。感谢您的领导:) – 2012-11-29 16:34:12

4

@ alexander-mera解决方案效果很好!

注意:也请务必将空格转换为+。例如,如果您正在搜索squire knight

SELECT title FROM movies WHERE to_tsvector(title) @@ to_tsquery('squire+knight:*') 
+0

使用'+'不适用于PosgreSQL 9.4.1。如果我使用'&',就像魅力一样。 – facundofarias 2015-10-27 10:15:33

0

的广泛的解决方案是使用PG的ts_rewrite功能设置一个别名表,对于交替匹配(见Query Rewriting)的工作原理。这包括像上面,而你也处理完全不同的情况下,像在那个链接搜索tree rat并获得结果squirrel

全部细节和解释的情况下,但它的要点是,你可以设置一个别名表2 ts_query列,并通过该表的查询与您的搜索,例如:

WHERE vectors @@ ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases') 

这是类似的:

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'); 

在这看起来更像是一个最终查询所得到PG中的词库设置,但每次添加内容时都不需要完全重新索引。正如你遇到的一些拼写变化和“当我搜索这个我期待这样的结果”的情况下,只需将它们快速添加到表格中就很容易。只要基于ts_rewrite的查询返回了预期的2列to_tsquery列,您就可以向该表中添加更多列。

当您深入了解该文档时,您还会看到有关性能调整的建议示例。在使用trigram进行纯速度和使用向量/查询/重写进行鲁棒性之间有一个平衡点。