121

Microsoft SQL Serverでは、「アクセントに依存しない」照合(データベース、テーブル、または列)を指定できます。これは、次のようなクエリが可能であることを意味します。

SELECT * FROM users WHERE name LIKE 'João'

名前のある行を検索しますJoao

unaccent_string contrib関数を使用してPostgreSQLの文字列からアクセントを取り除くことができることは知っていますが、PostgreSQLがこれらの「アクセントに依存しない」照合をサポートしているので、SELECT上記が機能するかどうか疑問に思います。

4

3 に答える 3

250

そのためにアクセントのないモジュールを使用してください-これは、リンクしているものとは完全に異なります。

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');

索引

この種のクエリにインデックスを使用するには、式にインデックスを作成します。ただしIMMUTABLE、Postgresはインデックスの関数のみを受け入れます。関数が同じ入力に対して異なる結果を返す可能性がある場合、インデックスは黙って壊れることがあります。

unaccent()だけでSTABLEはないIMMUTABLE

残念ながら、unaccent()は、ではSTABLEありませんIMMUTABLEpgsql-bugsに関するこのスレッドによると、これは3つの理由によるものです。

  1. 辞書の振る舞いに依存します。
  2. この辞書への有線接続はありません。
  3. したがって、電流にも依存し、search_path簡単に変化する可能性があります。

Web上のいくつかのチュートリアルでは、関数のボラティリティをに変更するように指示されていIMMUTABLEます。このブルートフォース方式は、特定の条件下で機能しなくなる可能性があります。

他の人は単純なIMMUTABLEラッパー関数を提案します(私が過去に自分でやったように)。

使用される辞書を明示的に宣言する2つのパラメーターを使用してバリアント を作成するかどうかについては、現在も議論が続いています。ここまたはここIMMUTABLEを読んでください。

もう1つの代替手段は、Githubで提供されているMusicbrainzによるIMMUTABLEunaccent()関数を備えたこのモジュールです。自分でテストしたことはありません。私はより良いアイデアを思いついたと思います:

今のところベスト

このアプローチは、他のソリューションが浮かんでいるのでより効率的で、より安全です。ハードワイヤードスキーマ修飾関数とディクショナリを使用して2パラメーター形式を実行するSQLラッパー関数
を作成します。IMMUTABLE

不変でない関数をネストすると関数のインライン化が無効になるため、(偽の)C関数のコピーにも基づいて宣言IMMUTABLEします。その唯一の目的は、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 SAFEPostgres9.5以前の両方の機能から削除します。

public拡張機能をインストールしたスキーマです(publicデフォルトです)。

明示的な型宣言(regdictionary)は、悪意のあるユーザーによる関数のオーバーロードされたバリアントによる架空の攻撃から防御します。

以前は、アクセントのないモジュールに付属しているSTABLE関数に基づいたラッパー関数を提唱していました。unaccent()その無効化された関数のインライン化。このバージョンは、以前ここにあった単純なラッパー関数よりも10倍高速に実行されます。
そして、それは、関数に追加された最初のバージョンの2倍の速さでしSET search_path = public, pg_tempた。辞書もスキーマ修飾できることがわかるまでは。それでも(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()常に1文字に置き換えられるため、手動で展開する必要があります(必要な場合)。

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
E A e a S

Postgres9.6でのアクセントのないこのアップデートを気に入るはずです

contrib/unaccentの標準unaccent.rulesファイルを拡張して、Unicodeで認識されているすべての発音区別符号を処理し、合字を正しく展開します(Thomas Munro、LéonardBenedetti)

大胆な強調鉱山。今、私たちは得る:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
OE AE oe ae ss

パターンマッチング

任意のパターンの場合、LIKEまたは任意のパターンで、これをPostgreSQL9.1以降ILIKEのモジュールと組み合わせます。pg_trgmトリグラム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また、「類似性」(%)と「距離」(<->の便利な演算子も提供します。

トリグラムインデックスは、~etalを使用した単純な正規表現もサポートしています。大文字と小文字を区別しないパターンマッチングILIKE

于 2012-06-13T01:51:07.453 に答える
10

いいえ、PostgreSQLはその意味で照合をサポートしていません

PostgreSQLは、そのような照合(アクセントに影響されないかどうか)をサポートしていません。これは、バイナリが等しい場合を除いて、比較で等しいものを返すことができないためです。これは、内部的にはハッシュインデックスなどに多くの複雑さをもたらすためです。このため、厳密な意味での照合は順序付けにのみ影響し、平等には影響しません。

回避策

語彙素にアクセントを付けない全文検索辞書。

FTSの場合、を使用して独自の辞書を定義できますunaccent

CREATE EXTENSION unaccent;

CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
  ALTER MAPPING FOR hword, hword_part, word
  WITH unaccent, simple;

次に、機能インデックスを使用してインデックスを作成できます。

-- Just some sample data...
CREATE TABLE myTable ( myCol )
  AS VALUES ('fóó bar baz'),('qux quz');

-- No index required, but feel free to create one
CREATE INDEX ON myTable
  USING GIST (to_tsvector('mydict', myCol));

これで、非常に簡単にクエリを実行できます

SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'

    mycol    
-------------
 fóó bar baz
(1 row)

も参照してください

それ自体はアクセントがない。

unaccentモジュールは、FTS統合なしで単独で使用することもできます。そのためには、 Erwinの回答を確認してください。

于 2018-05-30T01:33:17.413 に答える
2

PostgreSQLは照合のために基盤となるオペレーティングシステムに依存していると確信しています。新しい照合の作成と照合のカスタマイズをサポートします。しかし、あなたにとってどれだけの仕事ができるかはわかりません。(かなり多いかもしれません。)

于 2012-06-12T21:54:48.687 に答える