そのためにアクセントのないモジュールを使用します -これは、リンクしているものとは完全に異なります。
unaccentは、語彙素からアクセント(分音記号)を削除するテキスト検索辞書です。
データベースごとに1回インストール:
CREATE EXTENSION unaccent;
次のようなエラーが発生した場合:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
この関連する回答で指示されているように、データベースサーバーにcontribパッケージをインストールします。
他のものの間で、それはunaccent()
あなたがあなたの例で使うことができる機能を提供します(LIKE
必要と思われないところ)。
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
索引
そのようなクエリにインデックスを使用するには、式にインデックスを作成します。ただし、Postgres IMMUTABLE
はインデックスの関数のみを受け入れます。関数が同じ入力に対して異なる結果を返す可能性がある場合、インデックスが暗黙のうちに壊れることがあります。
unaccent()
だけでSTABLE
はないIMMUTABLE
残念ながら、unaccent()
だけではなくSTABLE
、IMMUTABLE
です。pgsql-bugsのこのスレッドによると、これは次の3つの理由によるものです。
- 辞書の動作に依存します。
- この辞書へのハードワイヤード接続はありません。
- したがって
search_path
、簡単に変更できる電流にも依存します。
Web上のいくつかのチュートリアルでは、関数のボラティリティをに変更するように指示していIMMUTABLE
ます。このブルートフォースメソッドは、特定の条件下で機能しなくなります。
他の人は単純なIMMUTABLE
ラッパー関数を提案します(私が過去に自分でやったように)
使用されるディクショナリを明示的に宣言する2つのパラメーター IMMUTABLE
を使用してバリアントを作成するかどうかについては、議論が続いています。こちらまたはこちらをお読みください。
別の方法としては、このモジュールになりIMMUTABLE unaccent()
MusicBrainzのことで機能 Githubの上に設けられました。自分でテストしていません。私はより良いアイデアを思いついたと思います:
今のところ
このアプローチは、他のソリューションが浮かんでいるほど効率的で、より安全です。スキーマで修飾された関数とディクショナリをハードワイヤードした2つのパラメーター形式を実行
するIMMUTABLE
SQLラッパー関数を作成します。
不変でない関数をネストすると関数のインライン展開が無効になるためIMMUTABLE
、同様に宣言された(偽の)C関数のコピーに基づいて関数を作成します。その唯一の目的は、SQL関数ラッパーで使用することです。単独で使用するためのものではありません。
C関数の宣言でディクショナリをハードワイヤーする方法がないため、高度な設定が必要です。(Cコード自体をハックする必要があります。)SQLラッパー関数はそれを行い、関数のインライン化と式のインデックスの両方を許可します。
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
ドロップPARALLEL SAFE
のPostgres 9.5歳以上のための両方の機能から。
public
拡張機能をインストールしたスキーマです(public
デフォルト)。
明示的な型宣言(regdictionary
)は、悪意のあるユーザーによる関数のオーバーロードされたバリアントによる仮想的な攻撃を防御します。
以前、私はに基づいてラッパー関数を提唱STABLE
機能unaccent()
unaccentモジュールに同梱。その無効化された関数のインライン化。このバージョンは、先ほど紹介した単純なラッパー関数よりも10倍速く実行されます。
そして、それはSET search_path = public, pg_temp
関数に追加された最初のバージョンの2倍の速さでした-私も辞書がスキーマ修飾できることを発見するまで。それでも(Postgres 12)、ドキュメントからあまり明白ではありません。
場合:あなたはCの関数を作成するために必要な権限が不足している、あなたが戻って次善の実装にあるIMMUTABLE
周りの機能ラッパーSTABLE
unaccent()
モジュールによって提供される機能:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
最後に、クエリを高速にするための式インデックス:
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
インデックスを再作成しないインプレースメジャーリリースアップグレードのように、関数または辞書を変更した後は、この関数に関連するインデックスを再作成することを忘れないでください。最近のメジャーリリースにはすべて、unaccent
モジュールの更新が含まれています。
インデックスに一致するようにクエリを調整します(そのため、クエリプランナーはそれを使用します)。
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
正しい式の関数は必要ありません。そこでは'Joao'
直接のようにアクセントのない文字列を提供することもできます。
より高速な関数は、式インデックスを使用したはるかに高速なクエリに変換されません。これは事前に計算された値で動作し、すでに非常に高速です。ただし、インデックスのメンテナンスとインデックスを使用しないクエリにはメリットがあります。
クライアントプログラムのセキュリティはPostgres 10.3 / 9.6.8などで強化されています。インデックスで使用する場合は、関数とディクショナリ名をスキーマ修飾する必要があります。見る:
合字
Postgresので9.5歳以上(あなたがそれを必要とする場合)「Œ」や「ß」のような合字を手動で拡張する必要があり、以来、unaccent()
常に代入し、単一の手紙を:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
あなたは愛するunaccentにこの更新プログラムを Postgresの中で9.6:
contrib/unaccent
の標準unaccent.rules
ファイルを拡張して、Unicodeで既知のすべての発音区別符号を処理し、合字を正しく展開します(Thomas Munro、LéonardBenedetti)
大胆な強調鉱山。今私たちは得ます:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
パターンマッチング
ためLIKE
、またはILIKE
任意のパターンで、モジュールと組み合わせるpg_trgm
のPostgreSQL 9.1以降です。トライグラムGIN(通常は望ましい)またはGIST式インデックスを作成します。GINの例:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
次のようなクエリに使用できます。
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
GINおよびGISTインデックスは、プレーンなbtreeよりも維持にコストがかかります。
左に固定されたパターンには、より簡単な解決策があります。パターンマッチングとパフォーマンスの詳細:
pg_trgm
また、「類似度」(%
)および「距離」(<->
)の便利な演算子も提供します。
Trigramインデックスは、~
et al。による単純な正規表現もサポートしています。と大文字と小文字を区別しないパターンマッチングILIKE
: