PostgreSQLは「アクセントを区別しない」照合をサポートしていますか?


98

Microsoft SQL Serverでは、「アクセントを区別しない」照合(データベース、テーブル、または列)を指定できます。つまり、次のようなクエリが可能です。

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

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

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


アクセントのないFTS辞書の作成については、この回答を参照してください。stackoverflow.com/ a / 50595181/124486
Evan Carroll

大文字と小文字を区別する検索、または大文字と小文字を区別しない検索が必要ですか?
エヴァンキャロル

回答:


204

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

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()だけではなくSTABLEIMMUTABLEです。pgsql-bugsのこのスレッドによると、これは次の3つの理由によるものです。

  1. 辞書の動作に依存します。
  2. この辞書へのハードワイヤード接続はありません。
  3. したがってsearch_path、簡単に変更できる電流にも依存します。

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

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

使用されるディクショナリを明示的に宣言する2つのパラメーター IMMUTABLEを使用してバリアントを作成するかどうかについては、議論が続いていますこちらまたはこちらをお読みください

別の方法としては、このモジュールになりIMMUTABLE unaccent()MusicBrainzのことで機能 Githubの上に設けられました。自分でテストしていません。私はより良いアイデアを思いついたと思います:

今のところ

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

不変でない関数をネストすると関数のインライン展開が無効になるため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


あなたのソリューションでは、インデックスが使用されていますか、それともインデックスを作成する必要がありますunaccent(name)か?
Daniel Serodio

@ErwinBrandstetter psql 9.1.4では、アクセントのない関数がINMUTABLEではなくSTABLEであるため、「インデックス式の関数にはIMMUTABLEのマークを付ける必要があります」と表示されます。何がお勧めですか?
e3matheus 2013年

1
@ e3matheus:私が提供した以前のソリューションをテストしていないことに罪悪感を感じたので、私は調査し、これまでの問題よりも新しい(IMHO)ソリューションで問題を解決しました。
Erwin Brandstetter 2013年

照合utf8_general_ciはこの種の問題に対する答えではありませんか?
2014

5
あなたの答えはPostgresのドキュメントと同じくらい素晴らしいです。
エレクトロタイプ

6

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

PostgreSQLは、そのような照合順序(アクセント記号を区別しないかどうかにかかわらず)をサポートしていません。なぜなら、バイナリで等しいものでない限り、比較結果が等しいとは限らないからです。これは、内部でハッシュインデックスなどの多くの複雑さを導入するためです。このため、厳密な意味での照合順序は順序にのみ影響し、等価性には影響しません。

回避策

Unaccents語彙素を検索する全文検索辞書。

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-統合することなく、それ自体でも使用することができアーウィンの答え


2

PostgreSQLは、照合のために基盤となるオペレーティングシステムに依存していると確信しています。新しい照合の作成照合のカスタマイズサポートされてます。しかし、あなたにとってどれほどの労力が必要かはわかりません。(かなりたくさんあります。)


1
現在、新しい照合のサポートは、基本的にオペレーティングシステムロケールのラッパーとエイリアスに限定されています。それは非常に基本的です。フィルター関数、カスタムコンパレーター、または真のカスタム照合に必要なものはサポートされていません。
クレイグリンガー、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.