如何使用Postgresql创建简单的模糊搜索?

时间:2011-10-11 17:29:08

标签: sql ruby-on-rails postgresql fuzzy-search

我的基于RoR的网站上的搜索功能有点问题。我有很多产品和一些CODE。此代码可以是任何字符串,如“AB-123-lHdfj”。现在我使用ILIKE运算符来查找产品:

Product.where("code ILIKE ?", "%" + params[:search] + "%")

工作正常,但找不到包含“AB123-lHdfj”或“AB123lHdfj”等代码的产品。

我该怎么做?可能是postgresql有一些字符串规范化功能,还是其他一些方法来帮助我? :)

2 个答案:

答案 0 :(得分:47)

Postgres提供了一个带有多个字符串比较函数的模块,例如soundex和metaphone。但是您需要使用levenshtein编辑距离功能。

Example:

test=# SELECT levenshtein('GUMBO', 'GAMBOL');
 levenshtein
-------------
           2
(1 row)

2是两个单词之间的编辑距离。当你对许多单词应用它并按编辑距离结果排序时,你将得到你正在寻找的模糊匹配类型。

尝试此查询示例:(当然,您自己的对象名称和数据)

SELECT * 
FROM some_table
WHERE levenshtein(code, 'AB123-lHdfj') <= 3
ORDER BY levenshtein(code, 'AB123-lHdfj')
LIMIT 10

此查询说:

从some_table中获取所有数据的前10个结果,其中代码值与输入'AB123-lHdfj'之间的编辑距离小于3.您将返回代码值在3个字符以内的所有行区别于'AB123-lHdfj'......

注意:如果收到如下错误:

function levenshtein(character varying, unknown) does not exist

使用以下方式安装fuzzystrmatch扩展程序:

test=# CREATE EXTENSION fuzzystrmatch;

答案 1 :(得分:38)

保罗告诉过你levenshtein()。这是一个非常有用的工具,但是对于大表来说它也很慢。它必须计算每一行搜索项的levenshtein距离,这是昂贵的。

首先,如果您的要求与示例所示一样简单,您仍然可以使用LIKE。只需使用-替换搜索字词中的所有%即可创建WHERE子句

WHERE code LIKE "%AB%123%lHdfj%"

而不是

WHERE code LIKE "%AB-123-lHdfj%"

如果你真正的问题是更复杂,那么你需要更快的东西 - 根据你的要求 - 有几种选择。

  • 当然有full text search。但在你的情况下这可能是一种矫枉过正。

  • 更有可能的候选人是pg_trgm。请注意,您可以将其与PostgreSQL 9.1中的LIKE组合使用。见blog post by Depesz 在此上下文中也非常有趣:该模块的similarity()函数或%运算符。更多:

  • 最后但并非最不重要的是,您可以实现一个手工编织的解决方案,其功能是规范化要搜索的字符串。例如,您可以转换AB1-23-lHdfj - &gt; ab123lhdfj,将其保存在其他列中,然后使用以相同方式转换的搜索字词进行搜索。

    或使用index on an expression代替冗余列。 (参与的函数必须是IMMUTABLE。)并且可能将其与上面的pg_tgrm结合起来。

模式匹配技术概述: