2

バックグラウンド

ユーザー入力またはデータベース フィールドにアクセント付き (UTF-8) 文字が含まれている場合でも、ユーザーが名前を入力すると、システムはそのテキストを照合する必要があります。これはpg_trgmモジュールを使用しています。

問題

コードは次のようになります。

  SELECT
    t.label
  FROM
    the_table t
  WHERE
    label % 'fil'
  ORDER BY
    similarity( t.label, 'fil' ) DESC

ユーザーがを入力filすると、クエリは一致しますが、一致filbertしませんfilé powder。(アクセントキャラのせい?)

失敗した解決策 #1

unaccent関数を実装して、クエリを次のように書き直そうとしました。

  SELECT
    t.label
  FROM
    the_table t
  WHERE
    unaccent( label ) % unaccent( 'fil' )
  ORDER BY
    similarity( unaccent( t.label ), unaccent( 'fil' ) ) DESC

これは のみを返しますfilbert

失敗した解決策 #2

提案どおり:

CREATE EXTENSION pg_trgm;
CREATE EXTENSION unaccent;

CREATE OR REPLACE FUNCTION unaccent_text(text)
  RETURNS text AS
$BODY$
  SELECT unaccent($1); 
$BODY$
  LANGUAGE sql IMMUTABLE
  COST 1;

テーブルの他のすべてのインデックスは削除されました。それで:

CREATE INDEX label_unaccent_idx 
ON the_table( lower( unaccent_text( label ) ) );

これは 1 つの結果のみを返します。

  SELECT
    t.label
  FROM
    the_table t
  WHERE
    label % 'fil'
  ORDER BY
    similarity( t.label, 'fil' ) DESC

質問

両方の結果が確実に返されるようにクエリを書き直す最善の方法は何ですか?

ありがとうございました!

関連している

http://wiki.postgresql.org/wiki/What%27s_new_in_PostgreSQL_9.0#Unaccent_filtering_dictionary

http://postgresql.1045698.n5.nabble.com/index-refuses-to-build-td5108810.html

4

2 に答える 2

5

pg_trgmモジュールによって提供される演算子クラスを使用していません。次のようなインデックスを作成します。

CREATE INDEX label_Lower_unaccent_trgm_idx
on test_trgm USING gist(lower(unaccent_text(label))gist_trgm_ops);

もともとここにGINインデックスがありましたが、類似性でソートされた値を返すことができるため、GiSTがこの種のクエリにおそらくさらに適していることを後で知りました。詳細:

クエリを使用するには、インデックス式と一致する必要があります。

SELECT label
FROM   the_table
WHERE  lower(unaccent_text(label)) % 'fil'
ORDER  BY similarity(label, 'fil') DESC -- it's ok to use original string here

ただし、%演算子によると、「filbert」と「filépowder」は実際には「fil」とあまり似ていません。私はあなたが本当に欲しいのはこれだと思います:

SELECTラベル
FROMthe_table
WHERE   lower(unaccent_text(label))~~'%fil%'
ORDER BY類似性(ラベル、'fil')DESC-ここで元の文字列を使用しても問題ありません

これにより、検索文字列を含むすべての文字列が検索され、%最初に演算子に従って最適な文字列が並べ替えられます。

そして、ジューシーな部分:PostgreSQL 9.1以降、式はGINまたはGiSTインデックスを使用できます。pg_trgm mouleのマニュアルを引用します:

PostgreSQL 9.1以降、これらのインデックスタイプは、たとえばLIKEおよびILIKEのインデックス検索もサポートします。


実際に%演算子を使用する場合:

相似演算子のしきい値を次のように下げてみましたか?%set_limit()

SELECT set_limit(0.1);

またはさらに低い?デフォルトは0.3です。追加をフィルタリングするしきい値が一致するかどうかを確認するだけです。

于 2012-04-19T23:07:35.560 に答える