的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