17

Rails の検索クエリで where/like 条件を変更するにはどうすればよいですか?

find(:all, :conditions => ["lower(name) LIKE ?", "%#{search.downcase}%"])

アクセントに関係なく結果が一致するようにするには?(例: メトロ = メトロ)。utf8を使っているのでto_asciiが使えません。制作は Heroku で行っています。

4

5 に答える 5

32

適切な解決策

PostgreSQL 9.1以降では、次のことができます。

CREATE EXTENSION unaccent;

関数を提供し、unaccent()必要なことを行います ( を除いてlower()、必要に応じて追加で使用してください)。この拡張機能に関するマニュアルを読んでください。

アンアクセントとインデックスの詳細:

貧乏人の解決策

をインストールできないunacccentが、関数を作成できる場合。ここからリストを編集し、時間をかけて追加しました。包括的ですが、完全ではありません。

CREATE OR REPLACE FUNCTION lower_unaccent(text)
  RETURNS text
  LANGUAGE sql IMMUTABLE STRICT AS
$func$
SELECT lower(translate($1
     , '¹²³áàâãäåāăąÀÁÂÃÄÅĀĂĄÆćčç©ĆČÇĐÐèéêёëēĕėęěÈÊËЁĒĔĖĘĚ€ğĞıìíîïìĩīĭÌÍÎÏЇÌĨĪĬłŁńňñŃŇÑòóôõöōŏőøÒÓÔÕÖŌŎŐØŒř®ŘšşșߊŞȘùúûüũūŭůÙÚÛÜŨŪŬŮýÿÝŸžżźŽŻŹ'
     , '123aaaaaaaaaaaaaaaaaaacccccccddeeeeeeeeeeeeeeeeeeeeggiiiiiiiiiiiiiiiiiillnnnnnnooooooooooooooooooorrrsssssssuuuuuuuuuuuuuuuuyyyyzzzzzz'
     ));
$func$;

クエリは次のように機能するはずです。

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)) LIKE 'bob%';

または使用しますCOLLATE "C"。見る:

于 2012-02-13T23:54:37.823 に答える
21

私のように、PostgreSQL の拡張機能を追加unaccentして Rails アプリケーションで動作させるのに問題がある人のために、作成する必要がある移行を次に示します。

class AddUnaccentExtension < ActiveRecord::Migration
  def up
    execute "create extension unaccent"
  end

  def down
    execute "drop extension unaccent"
  end
end

そしてもちろん、クエリrake db:migrateで関数を使用できるようになった後:またはunaccentunaccent(column) similar to ...unaccent(lower(column)) ...

于 2015-07-04T23:31:56.980 に答える
3

まず、postgresql-contrib をインストールします。次に、DB に接続して実行します。

CREATE EXTENSION unaccent;

DB の拡張機能を有効にします。

言語によっては、新しいルール ファイル (私の場合greek.rulesは にあります/usr/share/postgresql/9.1/tsearch_data) を作成するか、既存のファイルに追加する必要がありますunaccent.rules(非常に簡単です)。

独自の.rulesファイルを作成する場合は、デフォルトにする必要があります。

ALTER TEXT SEARCH DICTIONARY unaccent (RULES='greek');

この変更は永続的であるため、やり直す必要はありません。

次のステップは、この関数を利用するためのメソッドをモデルに追加することです。

単純な解決策の 1 つは、モデルで関数を定義することです。例えば:

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 で動作します。

更新情報
@Henrik N のフィードバックにより、潜在的な SQLi バックドアが修正されました

于 2013-12-24T23:03:27.470 に答える
2

StackExchange での検索に関連する 2 つの質問があります: https://serverfault.com/questions/266373/postgresql-accent-diacritic-insensitive-search

しかし、あなたが Heroku を使用しているので、これが適切であるとは思えません (専用のデータベース プランを持っていない限り)。

SOにもこれがあります:他の特殊文字を保持しながらアクセント/発音記号を文字列から削除します

ただし、これは、データがアクセントなしで保存されていることを前提としています。

それがあなたを正しい方向に向けることを願っています。

于 2012-02-12T10:12:48.377 に答える
0

Fooが検索対象のモデルでありname、が列であると仮定します。Postgres translateと ActiveSupport のtransliterateを組み合わせる。次のようなことができます:

Foo.where(
  "translate(
    LOWER(name),
    'âãäåāăąÁÂÃÄÅĀĂĄèééêëēĕėęěĒĔĖĘĚìíîïìĩīĭÌÍÎÏÌĨĪĬóôõöōŏőÒÓÔÕÖŌŎŐùúûüũūŭůÙÚÛÜŨŪŬŮ',
    'aaaaaaaaaaaaaaaeeeeeeeeeeeeeeeiiiiiiiiiiiiiiiiooooooooooooooouuuuuuuuuuuuuuuu'
  )
  LIKE ?", "%#{ActiveSupport::Inflector.transliterate("%qué%").downcase}%"
)
于 2016-01-23T07:14:43.813 に答える