web-dev-qa-db-ja.com

Postgresのトライグラムマッチが特定の文字で奇妙に機能する

Pg_trgmを使用してクエリを実行していますが、記号の違いを使用して検索すると、多くの1が一致します。次のクエリがあります。

SELECT my_column, similarity('$ Hello', my_column) AS sml
FROM my_table
WHERE my_column % '$ Hello'
ORDER BY sml DESC, my_column;

my_table、私は以下を持っています:

- Hello
? Hello
| Hello
$ Hello
! Hello
!? Hello

それらはすべて1の類似度一致で返されます。「$」または類似のものをエスケープする必要がありますか?

3
Lloyd Powell

他の回答では、トライグラムの類似性は英数字のみに基づいていることが明らかになりました。これが、すべての例が100%に一致する理由です。

トライグラムのGistまたはGINインデックスおよびを引き続き使用して、追加の_ORDER BY_式で目的のソート順を確立できる場合があります。実証済みのケース:

_SELECT my_column, similarity('$ Hello', my_column) AS sml
FROM   my_table
WHERE  my_column % '$ Hello'
ORDER  BY sml DESC
        , my_column <> '$ Hello'       -- !
        , my_column;
_

ブール式_my_column <> '$ Hello'_は、FALSETRUE、またはNULLに評価されます- this ソート順。したがって、完全一致( all 文字を考慮)が最初になります。そして、このクエリはまだトライグラムインデックスを使用できます。トライグラムGistインデックスは、LIMITを使用した"nearest neighbor"(KNN)検索も(まだ)サポートします。関連:

正確なユースケースと要件に応じて、さらに多くのことができます。例:

_...
ORDER  BY sml DESC
        , my_column <> '$ Hello'
        , my_column !~ '\$ Hello'            -- note $ escaped with \$
        , levenshtein(my_column , '$ Hello')
        , my_column;
_

同じトライグラムの類似性内で、これは完全一致を最初にソートし、次に strings 完全一致フレーズをストリング化します。そして、各サブグループ内では、最初に短いレーベンシュタイン距離が一致します。最後のタイブレーカーとしてアルファベット順。関連:

最後に重要なことですが、タグは全文検索です。しかし、あなたの例は、トライグラムの類似性(追加モジュール _pg_trgm_ によって提供される)に基づいています。これは、完全に別個のインフラストラクチャーとオペレーターを備えた大きく異なる概念です。代わりに実際の全文検索(およびそれを使用したフレーズ検索?)が必要な場合があります。

ただし、句読点の文字はノイズと見なされ、FTSではすべて同じように取り除かれます。同じ「問題」。 ts_debug()は、テキスト検索構成が特定のトークンを特定の文字列にどのように分類するかを示します(例ではsimple構成)。

_SELECT * FROM ts_debug('simple', '? Hello %&/( 123');
_

それは「デフォルトの」パーサー(現在は唯一のもの)から始まり、これらすべてをノイズとして解析して始めます...

3
SELECT show_trgm('$ Hello');

            show_trgm            
---------------------------------
 {"  h"," he",ell,hel,llo,"lo "}
(1 row)

SELECT show_trgm('- Hello');

            show_trgm            
---------------------------------
 {"  h"," he",ell,hel,llo,"lo "}
(1 row)

トライグラムが計算される前に、英数字以外のすべての文字が文字列から削除されます。

そのため、文字列の類似性は1。

シンボルの検索にトライグラムインデックスを使用することはできません。

ドキュメント は、最初の文にそれを持っています(私の強調):

pg_trgmモジュールは、トライグラムマッチングに基づいて英数字テキストの類似性を決定するための関数と演算子を提供します

4
Laurenz Albe

ドキュメントに記載されているように、句読点を無視することでpg_trgmが機能します。

冒険したい場合は、行を削除できます#define KEEPONLYALNUM「contrib/pg_trgm/trgm.h」から、再コンパイルして再インストールします。

これにより、既存のpg_trgmインデックスがサイレントに破損します。インデックスを再作成する必要があります。

3
jjanes