web-dev-qa-db-ja.com

フィールドで大文字と小文字を区別せず、アクセント/発音区別記号を区別しない検索を作成する

全文検索を使用しながら2つの関数を組み合わせたインデックスを作成することが理にかなっているかどうかを知りたいです:lower(name) and f_unaccent(name)ここで_f_unaccent_は、アクセントをなくすためのラッパーにすぎません関数は不変です。

私は機能しているインデックスがあります:_varchar_pattern_ops_を使用したf_unaccent(name)。私の質問は、lower関数とunaccent関数を組み合わせたインデックスがfull_text_search lower(f_unaccent(name))によってトリガーされることです。

lower関数が全文検索アルゴリズムの処理に役立つかどうかはわかりません。

3
Rubén_ic

まず、いくつかのことを明確にする必要があります。

パターン操作とトライグラム

このタイプのクエリは、varchar/text pattern_ops、

_foo LIKE 'bar%'
_

のクエリアンカーされていない検索パターン reqire trigram

_foo LIKE '%bar%'
_

インデックス内にあるクエリと同じシーケンスを維持する限り、どちらも関数式で機能します。

全文検索 は、まったく異なるものです。これは、ルートワードへのスタブ、小文字、ストップワードの削除、およびその他の多くのトリックによって、テキストを語彙素に変換します。読み続けます:

それ自体はアクセントがない(推奨しない)

残念ながらunaccentは「不変」ではなく「安定」にすぎません。したがって、unaccent(text)でインデックスを作成しようとすると、_functions in index expression must be marked IMMUTABLE_というエラーが発生します。これが、ラッパー_f_accent_を作成した理由だと思います。 ErwinsがStack Overflow で答えを見つけたからです。こんな感じ

_CREATE EXTENSION unaccent;
CREATE OR REPLACE FUNCTION f_unaccent(text)
  RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1)  -- schema-qualify function and dictionary
$func$
LANGUAGE sql
IMMUTABLE;

CREATE TABLE foo AS
  SELECT 'asdf'::text AS mytext;
CREATE INDEX ON foo (lower(f_unaccent(mytext)) text_pattern_ops);
_

または、トライグラムの場合、

_CREATE INDEX ON foo
USING gin(lower(f_unaccent(mytext)) gin_trgm_ops);
_

ここで、長いシーケンスlower(f_unaccent(mytext))を実行して機能させる必要があることを思い出してください。

_SELECT *
FROM foo
WHERE lower(f_unaccent(mytext)) LIKE '%whatever%';
_

FTS辞書でアクセントなし

その方法の代わりに、unaccentを使用してFTSを使用する辞書を作成します。カスタム辞書を使用すると、必要な処理が実行されます。 FTSは単語をトークンに変換するため、検索が非常に簡単かつ高速になります。

_CREATE EXTENSION unaccent; -- still required it plugs into FTS.

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

今、あなたはできるはずです

トークンとここで何が行われているのかを確認できます。

_select to_tsvector(
  'mydict',
  'Zoë and Renée are elected to the council of Cheese Eating Surrender Monkeys'
);
                                                             to_tsvector                                                             
-------------------------------------------------------------------------------------------------------------------------------------
 'and':2 'are':4 'cheese':10 'council':8 'eating':11 'elected':5 'monkeys':13 'of':9 'renee':3 'surrender':12 'the':7 'to':6 'zoe':1
(1 row)
_

そして、あなたはこのように単純にテーブルをクエリすることができます、

_SELECT *
FROM foo
WHERE to_tsvector('mydict', mytext) @@ 'cheese & council';
_

simpleを使用する必要もありません。列に1つの言語のステートメントのみが含まれている場合、 他の辞書のいずれか を使用して、物事を簡略化し、ストップワードを削除できます。

3
Evan Carroll