1

単語/文が文字列に含まれているかどうかを確認する必要があるpl/pgsqlスクリプトがあり、単語の境界を処理し、大文字と小文字を区別する必要があります。

例:

  • 文字列: "my label xx zz yy"、パターン: "my label"、MATCH
  • 文字列: "xx my label zz"、パターン: "my label"、MATCH
  • 文字列: "my labelxx zz"、パターン: "my label"、NO MATCH

したがって、明らかな解決策は、次のように正規表現を使用することです。

select _label ~* (E'\\y' || _pattern || E'\\y') into _match;

それは動作しますが、単純なものと比較して遅いです

select _label ilike '%' || _pattern || '%' into _match;

これは、私のスクリプトが A LOT を呼び出す関数にラップされ (数千万の場合、私は多くの再帰を行います)、この要件により、全体の実行時間は 2 倍になりました。

今私の質問は、これを実装するより速い方法はありますか?

ありがとう。

編集:これを使用して終了しました:

if _label ilike '%' || _pattern || '%' then
    select _label ~* (E'\\m' || _pattern || E'\\M') into _match;
end if;

そして、それは大幅に高速です。

4

1 に答える 1

2

全文検索機能を検討しますが、あなたが説明していることから、PostgreSQL arraysを使用してこれを実装する可能性があります。

最初に、ラベルを受け取り、それを小文字 (または必要に応じて大文字) にし、単語境界で分割し、配列を返す関数を定義します。言う:

CREATE OR REPLACE FUNCTION label_to_array(text) RETURNS text[] AS $$
SELECT regexp_split_to_array(lower($1), E'\\W');
$$ LANGUAGE sql IMMUTABLE;

$ select label_to_array('my label xx zz yy');
   label_to_array    
---------------------
 {my,label,xx,zz,yy}

次に、この関数にGIN インデックスを作成します。

CREATE INDEX sometable_label_array_key ON sometable
 USING GIN((label_to_array(label));

ここから、PostgreSQL は、「contains」などの配列演算子を含む多くのクエリにこのインデックスを使用できます。

SELECT *
FROM sometable
WHERE label_to_array(label) @> label_to_array('my label');

このクエリは に分割'my label'され{my,label}、インデックスを使用して を含む行のリストを検索し、それを を含むmy行のリストと交差させてlabel、結果を返します。これは元のクエリとまったく同じではありませんが (順序をチェックしないため)、インデックスを使用してテーブル内のほとんどの行を削除するため、最後に元のチェックを追加すると問題なく機能します。

SELECT *
FROM sometable
WHERE label_to_array(label) <@ label_to_array('my label')
AND label ~* (E'\\y' || 'my label' || E'\\y');
于 2012-11-05T15:32:33.973 に答える