的Rails 3.1如何修改一个地方/像在Rails的搜索查询条件:Postgres的口音不敏感的LIKE搜索中在Heroku
find(:all, :conditions => ["lower(name) LIKE ?", "%#{search.downcase}%"])
,这样的结果是,不论口音的匹配? (例如métro= metro)。因为我使用的是utf8,所以我不能使用“to_ascii”。生产在Heroku上运行。
的Rails 3.1如何修改一个地方/像在Rails的搜索查询条件:Postgres的口音不敏感的LIKE搜索中在Heroku
find(:all, :conditions => ["lower(name) LIKE ?", "%#{search.downcase}%"])
,这样的结果是,不论口音的匹配? (例如métro= metro)。因为我使用的是utf8,所以我不能使用“to_ascii”。生产在Heroku上运行。
如果你能够创建一个函数,你可以用这一个。我编制了从here开始的列表并随着时间的推移添加到列表中。它非常完整。你甚至可能要删除一些字符:
CREATE OR REPLACE FUNCTION lower_unaccent(text)
RETURNS text AS
$func$
SELECT lower(translate($1
, '¹²³áàâãäåāăąÀÁÂÃÄÅĀĂĄÆćčç©ĆČÇĐÐèéêёëēĕėęěÈÊËЁĒĔĖĘĚ€ğĞıìíîïìĩīĭÌÍÎÏЇÌĨĪĬłŁńňñŃŇÑòóôõöōŏőøÒÓÔÕÖŌŎŐØŒř®ŘšşșߊŞȘùúûüũūŭůÙÚÛÜŨŪŬŮýÿÝŸžżźŽŻŹ'
, '123aaaaaaaaaaaaaaaaaaacccccccddeeeeeeeeeeeeeeeeeeeeggiiiiiiiiiiiiiiiiiillnnnnnnooooooooooooooooooorrrsssssssuuuuuuuuuuuuuuuuyyyyzzzzzz'
));
$func$ LANGUAGE sql IMMUTABLE;
您的查询应该像那:
find(:all, :conditions => ["lower_unaccent(name) LIKE ?", "%#{search.downcase}%"])
左锚搜索,你可以利用的非常快速的结果对功能的指数:
CREATE INDEX tbl_name_lower_unaccent_idx
ON fest (lower_unaccent(name) text_pattern_ops);
对于这样的查询:
SELECT * FROM tbl WHERE (lower_unaccent(name)) ~~ 'bob%'
在的PostgreSQL 9.1+,有必要的权限,你可以:
CREATE EXTENSION unaccent;
它提供了一个功能unaccent()
,做你需要(除了lower()
什么,如果需要,另外使用)。阅读manual about this extension。
也可用于PostgreSQL 9.0但CREATE EXTENSION
语法是9.1中新增的。
更多unaccent和索引:
所有的嗨Erwin,谢谢你。我在9.1上,所以CREATE EXTENSION unaccent;看起来像前进的道路。你会如何建议我通过我的Rails应用激活它(因为我需要这种情况发生在Heroku以及我的开发环境)......谢谢! – user1051849 2012-02-14 10:20:11
如果你被困在9.0,如果你执行C:\ Program Files \ PostgreSQL \ 9.0 \ share \ contrib \ unaccent.sql – Edo 2014-10-21 13:59:24
(3年后:),Heroku还包括'unaccent':https:/ /devcenter.heroku.com/articles/heroku-postgres-extensions-postgis-full-text-search您可以通过运行'echo'show extwlist.extensions'| heroku pg:psql' – 2015-01-23 20:06:35
有2点与您的StackExchange搜索的问题: https://serverfault.com/questions/266373/postgresql-accent-diacritic-insensitive-search
但是当你是在Heroku上,我怀疑这是一个很好的匹配(除非你有一个专门的数据库计划)。
SO上还有这个:Removing accents/diacritics from string while preserving other special chars。
但是这里假设你的数据没有任何口音存储。
我希望它能指引您正确的方向。
嗨皮埃尔 - 谢谢 - 是的,我看到了这两个,但不幸的是,在这种情况下,也没有帮助我。 – user1051849 2012-02-12 10:47:38
首先,你安装PostgreSQL-的contrib。然后,您连接到您的数据库,并执行:
CREATE EXTENSION unaccent;
启用扩展您的数据库。
根据你的语言,你可能需要创建一个新的规则文件(在我的情况greek.rules
,位于/usr/share/postgresql/9.1/tsearch_data
),或者只是附加到现有unaccent.rules
(很简单)。
如果你创建自己的.rules
文件,你需要使它默认:
ALTER TEXT SEARCH DICTIONARY unaccent (RULES='greek');
这种变化是持久的,所以你不必重做。
下一步是向模型添加一个方法来使用这个函数。
一个简单的解决方案是在模型中定义一个函数。例如:
class Model < ActiveRecord::Base
[...]
def self.unaccent(column,value)
a=self.where('unaccent(?) LIKE ?', column, "%value%")
a
end
[...]
end
然后,我可以简单地调用:
Model.unaccent("name","text")
而不模型定义调用相同的命令将是作为纯为:
Model.where('unaccent(name) LIKE ?', "%text%"
注:上面的示例已经过测试,适用于postgres9.1,Rails 4.0,Ruby 2.0。
UPDATE INFO
固定电位SQLI后门感谢@Henrik N为反馈
危险!如果你只是将值插入到SQL中,并且这个值是用户提供的,那么你可以打开自己的SQL注入。这是更安全的,因为Rails会为你逃避:Model.where(“unaccent(name)LIKE unaccent(?)”,“%#{value}%”)或者'Model.where(“unaccent(name) LIKE?“,”%#{value}%“),如果你不关心不值的话。 – 2015-01-23 20:29:45
你是对的,当然...我现在不会这样做,但这是旧的..我会修复它,谢谢注意 – 2015-01-23 21:51:48
没问题。嗯,我怀疑使用'unaccent(?)'列名将它视为一个字符串而不是列名,但我不确定。 – 2015-01-25 15:33:36
对于那些像我谁是有麻烦添加unaccent
扩展PostgreSQL和得到它与Rails应用程序时,这里是迁移您需要创建:
class AddUnaccentExtension < ActiveRecord::Migration
def up
execute "create extension unaccent"
end
def down
execute "drop extension unaccent"
end
end
,当然,rake db:migrate
后,你将能够使用unaccent
功能在查询:unaccent(column) similar to ...
或unaccent(lower(column)) ...
假设Foo
是你正在寻找对抗和name
是列模型。结合Postgres translate和ActiveSupport的transliterate。你可以这样做:
Foo.where(
"translate(
LOWER(name),
'âãäåāăąÁÂÃÄÅĀĂĄèééêëēĕėęěĒĔĖĘĚìíîïìĩīĭÌÍÎÏÌĨĪĬóôõöōŏőÒÓÔÕÖŌŎŐùúûüũūŭůÙÚÛÜŨŪŬŮ',
'aaaaaaaaaaaaaaaeeeeeeeeeeeeeeeiiiiiiiiiiiiiiiiooooooooooooooouuuuuuuuuuuuuuuu'
)
LIKE ?", "%#{ActiveSupport::Inflector.transliterate("%qué%").downcase}%"
)
我想知道,你使用了什么解决方案?是否有仅基于导轨的解决方案?谢谢! – ipegasus 2013-08-02 19:49:21