web-dev-qa-db-ja.com

PostgreSQL全文検索でハイフネーションされた単語を検索する方法は?

「good-morning」、「good-evening」などのハイフン付きの単語を検索する必要があります。

私のクエリは:

select id, ts_headline(content,
                       to_tsquery('english','good-morning'),
                       'HighlightAll=true MaxFragments=100 FragmentDelimiter=$') 
from table 
where ts_content @@ to_tsquery('english','good-morning');

このクエリを実行すると、'good'および'morning'の結果も個別に取得されます。しかし、正確に一致する単語とフラグメントが必要です。
(ために ts_content同じデフォルト設定englishを使用してtsvectorを作成しました。)

PostgreSQLの全文検索でこのようなハイフン付きの単語を検索するにはどうすればよいですか?

7
user3098231

ここでのキーワードはフレーズ検索で、Postgresで導入されています9.6

tsquery FOLLOWED BY演算子_<->_ または 関連する_<N>_演算子 。あるいは、関数phraseto_tsquery()を使用してtsqueryを生成します。
マニュアルの引用 、それ...

句読点を無視して語句を検索するtsqueryを生成します

および:

_phraseto_tsquery_(AND)演算子ではなく、存続する単語の間に_plainto_tsquery_(FOLLOWED BY)演算子を挿入することを除いて、_<->_は_&_とほとんど同じように動作します。また、ストップワードは単に破棄されるのではなく、_<N>_演算子ではなく_<->_演算子を挿入することで説明されます。 FOLLOWED BY演算子は、すべての語彙素の存在だけでなく語彙素の順序もチェックするため、この関数は正確な語彙素シーケンスを検索するときに役立ちます。

クエリは次のように機能します。

_select id
     , ts_headline(content, phraseto_tsquery('english', 'good-morning')
                          , 'HighlightAll=true MaxFragments=100 FragmentDelimiter=$') 
from   tbl 
where  ts_content @@ phraseto_tsquery('english','good-morning');
_

phraseto_tsquery('english', 'good-morning')はこれを生成しますtsquery

_'good-morn' <-> 'good' <-> 'morn'
_

「おはよう」はasciihword(ハイフン付きASCII Word))として識別されるため、語幹処理された完全なWordがコンポーネントの前に追加されます The manual:

パーサーが同じテキストの断片から重複するトークンを生成する可能性があります。例として、ハイフンで区切られたWordは、Word全体と各コンポーネントの両方として報告されます:(例に続いて)

to_tsvector()は基本的に反対側でも同じことを行うため、すべてが一致します。これにより、ハイフン付きの単語を使用したきめの細かいオプションが可能になります。上記は、ハイフン(または同じものに派生するバリアント)を含む「おはよう」のみを検出します。 「good」の後に「morn」が続くすべての文字列(または同じものに派生するバリアント)を検索するには、phraseto_tsquery('english','good morning')を使用して次のtsqueryを生成します。_'good' <-> 'morn'_

OTOH、次のような別のフィルターを追加することで、完全一致を強制できます。

_...
AND content ~* 'good-morning'  -- case insensitive regexp match
_

または:

_...
AND content ILIKE '%good-morning%'
_

人間の目には少し冗長に思えますが、この方法でfast全文索引サポートandexactが一致します。

後者はほとんど同じですが、異なる(少ない)文字はLIKEパターンで特別な意味を持ち、エスケープする必要がある場合があります。関連:

演算子_<N>_を示す例:

phraseto_tsquery('english', 'Juliet and the Licks')はこれを生成しますtsquery

_'juliet' <3> 'lick'
_

_<3>_は、lickjulietに続く3番目の語彙素でなければならないことを意味します。

7