RoRベースのサイトの検索機能に少し問題があります。いくつかのコードを含む多くのProdutsがあります。このコードには、「AB-123-lHdfj」などの任意の文字列を使用できます。次に、ILIKE演算子を使用して製品を検索します。
Product.where("code ILIKE ?", "%" + params[:search] + "%")
正常に動作しますが、「AB123-lHdfj」や「AB123lHdfj」などのコードを持つ製品は見つかりません。
これのために何をすべきですか? postgresqlには文字列の正規化機能や他の方法がありますか? :)
Postgresは、soundexやmetaphoneなどの文字列比較機能を備えたモジュールを提供します。ただし、 levenshtein 編集距離関数を使用する必要があります。
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;
ポールは levenshtein()
について話しました。これは非常に便利なツールですが、大きなテーブルでは非常に遅くなります。各行の検索語からレベンシュタイン距離を計算する必要があり、それは高価です。
まず、if要件が例に示されているように単純である場合でも、LIKE
を使用できます。検索用語の_-
_を_%
_に置き換えて、WHERE
句を作成します。
_WHERE code LIKE "%AB%123%lHdfj%"
_
の代わりに
_WHERE code LIKE "%AB-123-lHdfj%"
_
実際の問題がより複雑で、要件に応じてより高速なものが必要な場合、いくつかのオプションがあります。
もちろん、 全文検索 があります。しかし、これはあなたの場合にはやり過ぎかもしれません。
より可能性の高い候補は pg_trgm です。 PostgreSQL 9.1では、これをLIKE
と組み合わせることができることに注意してください。こちらをご覧ください Depeszによるブログ投稿 。
このコンテキストでも非常に興味深い:そのモジュールのsimilarity()
関数または_%
_演算子。もっと:
最後になりましたが、検索する文字列をnormalizeする機能を備えた手編みのソリューションを実装できます。たとえば、_AB1-23-lHdfj
_-> _ab123lhdfj
_を変換し、追加の列に保存して、同じ方法で変換された検索語で検索できます。
または、冗長列の代わりに 式のインデックス を使用します。 (関与する関数はIMMUTABLE
である必要があります。)そして、おそらくそれを上記の_pg_tgrm
_と組み合わせることができます。
パターンマッチング手法の概要: