44

RoR ベースのサイトの検索機能に少し問題があります。私はいくつかのコードを持つ多くの製品を持っています。このコードは、「AB-123-lHdfj」のような任意の文字列にすることができます。今、私はILIKE演算子を使って製品を見つけます:

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

正常に動作しますが、「AB123-lHdfj」や「AB123lHdfj」などのコードを持つ製品を見つけることができません。

これにはどうすればよいですか?Postgresには、文字列の正規化機能、または私を助ける他の方法がありますか?

4

2 に答える 2

61

Postgres は、soundex や metaphone などのいくつかの文字列比較関数を備えたモジュールを提供します。ただし、レーベンシュタイン編集距離関数を使用する必要があります。

Example:

test=# SELECT levenshtein('GUMBO', 'GAMBOL');
 levenshtein
-------------
           2
(1 row)

2、2 つの単語間の編集距離です。これをいくつかの単語に対して適用し、編集距離の結果で並べ替えると、探しているタイプのあいまい一致が得られます。

このクエリ サンプルを試してください: (もちろん、独自のオブジェクト名とデータを使用して)

SELECT * 
FROM some_table
WHERE levenshtein(code, 'AB123-lHdfj') <= 3
ORDER BY levenshtein(code, 'AB123-lHdfj')
LIMIT 10

このクエリは次のように述べています。

コード値と入力 'AB123-lHdfj' の間の編集距離が 3 未満である some_table からのすべてのデータの上位 10 件の結果を教えてください。 AB123-lHdfj'...

注: 次のようなエラーが発生した場合:

function levenshtein(character varying, unknown) does not exist

fuzzystrmatch次を使用して拡張機能をインストールします。

test=# CREATE EXTENSION fuzzystrmatch;
于 2011-10-11T17:35:02.150 に答える
49

ポールはあなたにについて話しlevenshtein()ました。これは非常に便利なツールですが、大きなテーブルでは非常に遅くなります。すべての行について、検索語からのレーベンシュタイン距離を計算する必要があります。これは高価であり、インデックスを使用できません。「加速」バリアントlevenshtein_less_equal()は、長い文字列の場合は高速ですが、インデックスがサポートされていないと低速です。

例が示すように要件が単純な場合でも、を使用できますLIKE-検索語のいずれかを句%内に置き換えるだけです。WHEREしたがって、代わりに:

WHERE code ILIKE '%AB-123-lHdfj%'

使用する:

WHERE code ILIKE '%AB%123%lHdfj%'

または、動的に:

WHERE code ILIKE '%' || replace('AB-123-lHdfj', '-', '%') || '%'

%LIKEパターン内は0-n文字を表します。または_、1文字だけに使用します。または、よりスマートな一致のために正規表現を使用します。

WHERE code ~* 'AB.?123.?lHdfj'

.?...0または1文字

または:

WHERE code ~* 'AB\-?123\-?lHdfj'

\-?...0または1ダッシュ

LIKEまたは正規表現パターンの特殊文字をエスケープすることをお勧めします。見る:


実際の問題がより複雑で、より高速なものが必要な場合は、要件に応じてさまざまなオプションがあります。

パターンマッチング手法の概要:

于 2011-10-12T23:28:13.210 に答える