如何使用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或正则表达式匹配的模式
- 具有连接和顺序的独特记录
- ActiveRecord可以远程连接到PostgreSQL并保护数据库密码吗?
- Rails和Postgres Hstore:你能在迁移中添加索引吗?
- 使用ActiveRecord的哈希数组
- Rails 3.2 Postgres保存错误“ActiveRecord :: StatementInvalid:PG ::错误:错误:位置5’T’附近的语法错误”
- DB上的错误:迁移“未初始化的常量DeviseCreateUsers”
- Rails – postgres上的gmaps4rails gem
- Postgres查询包含内容的JSON数组
- 你已经拿破了包 – Postgres gem for rails