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

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

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

它工作正常,但找不到像“AB123-lHdfj”或“AB123lHdfj”这样的代码的产品。

我该怎么办? 可能postgresql有一些字符串规范化function,还是其他一些方法来帮助我? 🙂

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; 

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

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

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

代替

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

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

  • 当然还有全文搜索 。 但在你的情况下,这可能是一种矫枉过正。

  • 更可能的候选人是pg_trgm 。 请注意,您可以将它与PostgreSQL 9.1中的LIKE结合使用。 请参阅Depesz的这篇博客文章 。
    在此上下文中也非常有趣:该模块的similarity()函数或%运算符。 更多:

    • PostgreSQL LIKE查询性能变化
  • 最后但并非最不重要的是,您可以实现一个手工编织的解决方案,其中包含一个函数来规范化要搜索的字符串。 例如,您可以转换AB1-23-lHdfj – > ab123lhdfj ,将其保存在其他列中,并使用以相同方式转换的搜索项进行搜索。

    或者在表达式而不是冗余列上使用索引 。 (涉及的函数必须是IMMUTABLE 。)并且可能将它与上面的pg_tgrm结合起来。

模式匹配技术概述:

  • 与PostgreSQL中的LIKE,SIMILAR TO或正则表达式匹配的模式